home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir34 / thindi.zip / THISRC.ZIP / THINDISK.C < prev    next >
C/C++ Source or Header  |  1994-02-14  |  87KB  |  2,674 lines

  1. //===========================================================
  2. // ThinDisk - A Program to help thin out disk clutter
  3. // Copyright (C) 1994 Douglas Boling
  4. //
  5. // Revision History:
  6. //
  7. // 1.0   Initial Release
  8. //
  9. //===========================================================
  10. // Returns no. of elements
  11. #define dim(x) (sizeof(x) / sizeof(x[0]))   
  12.  
  13. #define  SPECNAMELEN   32
  14.  
  15. //-----------------------------------------------------------
  16. // Include files
  17. //-----------------------------------------------------------
  18. #include "windows.h"
  19. #include "dos.h"
  20. #include "stdlib.h"
  21. #include "stdio.h"
  22. #include "string.h"
  23. #include "direct.h"
  24. #include "ctype.h"
  25.  
  26. #include "thindisk.h"
  27. #include "statbar.h"
  28. //-----------------------------------------------------------
  29. // Global data
  30. //-----------------------------------------------------------
  31. // Message dispatch table for MainWindowProc
  32. struct decodeUINT MainMessages[] = {
  33.     WM_CREATE, DoCreateMain,
  34.     WM_DRAWITEM, DoDrawItemMain,
  35.     WM_MEASUREITEM, DoMeasureItemMain,
  36.     WM_INITMENU, DoInitMenuMain,
  37.     WM_SETFOCUS, DoSetFocusMain,
  38.     WM_SIZE, DoSizeMain,
  39.     WM_COMMAND, DoCommandMain,
  40.     WM_CLOSE, DoCloseMain,
  41.     WM_DESTROY, DoDestroyMain,
  42. };
  43. // Command Message dispatch for MainWindowProc
  44. struct decodeCMD MainMenuItems[] = {
  45. //    IDD_FLIST, DoMainCtlFList,
  46.     IDM_REFRESH, DoMainMenuRefresh,
  47.     IDM_MOVE, DoMainMenuMCD,
  48.     IDM_COPY, DoMainMenuMCD,
  49.     IDM_DELETE, DoMainMenuMCD,
  50.     IDM_EXIT, DoMainMenuExit,
  51.     IDM_FIND, DoMainMenuFind,
  52.     IDM_FINDNEXT, DoMainMenuFind,
  53.     IDM_FINDPREV, DoMainMenuFind,
  54.     IDM_SORTUPDN, DoMainMenuInvert,
  55.     IDM_SHOWSIZE, DoMainMenuShow,
  56.     IDM_SHOWDATE, DoMainMenuShow,
  57.     IDM_SHOWATTRIB, DoMainMenuShow,
  58.     IDM_SHOWPATH, DoMainMenuShow,
  59.     IDM_SORTNAME, DoMainMenuSort,
  60.     IDM_SORTEXT, DoMainMenuSort,
  61.     IDM_SORTSIZE, DoMainMenuSort,
  62.     IDM_SORTDATE, DoMainMenuSort,
  63.     IDM_INCLUDE, DoMainMenuInclude,
  64.     IDM_INCLUDEEDIT, DoMainMenuIncludeEdit,
  65.     IDM_INCLUDEDEL, DoMainMenuIncludeDel,
  66.     IDM_INCLUDEALL, DoMainMenuIncludeSet,
  67.     IDM_INCLUDEALL+1, DoMainMenuIncludeSet,
  68.     IDM_INCLUDEALL+2, DoMainMenuIncludeSet,
  69.     IDM_INCLUDEALL+3, DoMainMenuIncludeSet,
  70.     IDM_INCLUDEALL+4, DoMainMenuIncludeSet,
  71.     IDM_INCLUDEALL+5, DoMainMenuIncludeSet,
  72.     IDM_INCLUDEALL+6, DoMainMenuIncludeSet,
  73.     IDM_INCLUDEALL+7, DoMainMenuIncludeSet,
  74.     IDM_ABOUT, DoMainMenuAbout,
  75. };
  76. HANDLE    hInst;
  77. HWND        hMain;
  78. UINT        wVersion = 10;
  79. BOOL        fFirst = TRUE;
  80.  
  81. char    szAppName[] = "WinThinDisk";         // Application name
  82. char    szTitleText[] = "ThinDisk";          // Application window title
  83. char    szMenuName[] = "WinThinDiskMenu";    // Menu name
  84. char    szIconName[] = "WinThinDiskIcon";    // Icon name
  85. char    szProfileName[] = "ThinDisk.ini";    // INI file name
  86.  
  87. FARPROC    lpfnOldLBoxWndProc;               //Old Listbox procedure
  88. BOOL         fFindNew = TRUE;                  //First time Find pressed flag
  89. BOOL         fSelOS = FALSE;                   //Some selected Listbox items not visible
  90. INT sOldIncCnt = 1;                        //Flag used to regen include set menu
  91. UINT fViewFlags = 0x0f;                    //Default view set flags
  92. //
  93. //Virtual List box stuff
  94. //
  95. INT sListSize;
  96. INT sLItemHeight = 1;
  97. //
  98. // Global pointers used in recursive directory scan
  99. //
  100. BOOL fSearching = FALSE;
  101. LPLPMYDIRENTRY lpIndexPtr;
  102. LPLPMYDIRENTRY lpDestPtr;
  103. char szSearchDir[MAXFNAMELEN] = "";
  104. char szStatText[80] = "";
  105. char *pszStatEnd;
  106. //
  107. // Directory entry block items
  108. //
  109. LPMYDIRENTRY lpDirEntry;
  110. LPBUFFHDR lpCurrBuff;
  111. BUFFHDR Buff = {0,0,0};
  112. INT sMasterCount = 0;
  113. UINT usLevel;
  114. UINT usItteration, usGoal, usLastStat;
  115. //
  116. // Include array stuff
  117. //
  118. INT sCount = 0, sDirCnt = 0;
  119. INT sIncCount;
  120. INCSPEC incArray[MAXINCSPECS];
  121. LPINCSPEC lpCurrInc;
  122. //
  123. // Sorting arrays
  124. //
  125. BOOL fSortUp = FALSE;
  126. UINT hMasterSeg = 0;
  127. INT sSortIndex = 0;
  128. UINT hSortSeg[SORTTYPES] = {0,0,0,0};
  129. SORTFUNC pSortFunc[SORTTYPES] = {SortName, SortExt, SortSize, SortDate};
  130. char *szSortLabel[SORTTYPES] = {"name", "extension", "size", "date"};
  131. //File functions
  132. FILEFUNC pFileFunc[FUNCTYPES] = {CopyFile, MoveFile, DeleteFile};
  133. //============================================================
  134. // WinMain -- entry point for this application from Windows.
  135. //============================================================
  136. INT APIENTRY WinMain(HANDLE hInstance, HANDLE hPrevInstance, 
  137.                      LPSTR lpCmdLine, INT nCmdShow) {
  138.     MSG    msg;
  139.     INT    rc;
  140.     HANDLE hAccel;
  141.  
  142.     hInst = hInstance;
  143.     //
  144.     // If first instance, perform any init processing
  145.     //
  146.    if(!hPrevInstance)
  147.         if((rc = InitApp(hInstance)) != 0)
  148.             return rc;
  149.     //
  150.     // Initialize this instance
  151.     //
  152.     if((rc = InitInstance(hInstance, lpCmdLine, nCmdShow)) != 0)
  153.         return rc;
  154.     //
  155.     // Application message loop
  156.     //
  157.     hAccel = LoadAccelerators (hInstance, szAppName);
  158.     while (GetMessage (&msg, NULL, 0, 0)) {
  159.         if (!TranslateAccelerator (hMain, hAccel, &msg)) {
  160.             TranslateMessage(&msg);
  161.             DispatchMessage(&msg);
  162.         }    
  163.     }
  164.     // Instance cleanup
  165.     return TermInstance(hInstance, msg.wParam);
  166. }
  167. //-----------------------------------------------------------
  168. // InitApp - Global initialization code for this application.
  169. //-----------------------------------------------------------
  170. INT InitApp(HANDLE hInstance) {
  171.     WNDCLASS     wc;
  172.     //
  173.     // Register App Main Window class
  174.     //        
  175.     wc.style = 0;                             // Window style
  176.     wc.lpfnWndProc = MainWndProc;             // Callback function
  177.     wc.cbClsExtra = 0;                        // Extra class data
  178.     wc.cbWndExtra = 0;                        // Extra window data
  179.     wc.hInstance = hInstance;                 // Owner handle
  180.     wc.hIcon = LoadIcon(hInst, szIconName);   // Application icon
  181.     wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Default cursor
  182.     wc.hbrBackground = COLOR_WINDOW + 1;
  183.     wc.lpszMenuName =  szMenuName;            // Menu name
  184.     wc.lpszClassName = szAppName;             // Window class name
  185.     if (RegisterClass(&wc) == 0)
  186.         return 1;
  187.     
  188.     StatusBarInit (hInstance);
  189.     return 0;
  190. }
  191. //-----------------------------------------------------------
  192. // InitInstance - Instance initialization code for this app.
  193. //-----------------------------------------------------------
  194. INT InitInstance(HANDLE hInstance, LPSTR lpCmdLine, INT nCmdShow) {
  195.    INT x,y, cx, cy;
  196.     HDC hdc;
  197.     TEXTMETRIC tm;
  198.     INT sField[4];
  199.     char szIn[40], szTemp[33];
  200.     //
  201.     //Determine the size of the system font to set the sizes of the
  202.     //window controls.
  203.     //
  204.     hdc = GetDC (NULL);
  205.     SelectObject (hdc, GetStockObject (SYSTEM_FONT));
  206.     GetTextMetrics (hdc, &tm);
  207.     sLItemHeight = tm.tmHeight + tm.tmExternalLeading;
  208.     ReleaseDC (NULL, hdc);
  209.     //Read INI file info
  210.     x = GetPrivateProfileInt (szAppName, PRO_XPOS, CW_USEDEFAULT,
  211.                               szProfileName);
  212.     y = GetPrivateProfileInt (szAppName, PRO_YPOS, CW_USEDEFAULT,
  213.                               szProfileName);
  214.     cx = GetPrivateProfileInt (szAppName, PRO_XSIZE, CW_USEDEFAULT,
  215.                               szProfileName);
  216.     cy = GetPrivateProfileInt (szAppName, PRO_YSIZE, CW_USEDEFAULT,
  217.                               szProfileName);
  218.     //Setup initial include array 
  219.     lpCurrInc = &incArray[0];
  220.     sIncCount = GetPrivateProfileInt (szAppName, PRO_INCCNT, 0, szProfileName);
  221.     if (sIncCount) {
  222.         for (x = 0; x < sIncCount; x++) {
  223.             itoa (x, szIn, 10);
  224.             GetPrivateProfileString (szIn, PRO_SPECNAME, "Inc Spec", 
  225.                                      lpCurrInc->szSpecName, 
  226.                                      sizeof (lpCurrInc->szSpecName), szProfileName);
  227.             GetPrivateProfileString (szIn, PRO_FILESPEC, "*.*", lpCurrInc->szFileSpec,
  228.                                      sizeof (lpCurrInc->szFileSpec), szProfileName);
  229.             GetPrivateProfileString (szIn, PRO_INCSIZE, "0", szTemp, 
  230.                                      sizeof (szTemp), szProfileName);
  231.             lpCurrInc->lIncSize = atol (szTemp);
  232.             lpCurrInc->usIncDate = GetPrivateProfileInt (szIn, PRO_INCDATE, 
  233.                                    0x21, szProfileName);
  234.             lpCurrInc->usIncFlags = GetPrivateProfileInt (szIn, PRO_INCFLAGS, 
  235.                                    _A_RDONLY | _A_ARCH | _A_HIDDEN | _A_SYSTEM,
  236.                                  szProfileName);
  237.             lpCurrInc->fScrnFlags = GetPrivateProfileInt (szIn, PRO_SCRNFLAGS, 
  238.                                               SCRN_INCEMPTYDIRS, szProfileName);
  239.             lpCurrInc++;
  240.         }
  241.         lpCurrInc = &incArray[0];
  242.     } else {    
  243.         sIncCount = 1;
  244.         memset (&incArray[0], 0, sizeof (INCSPEC));
  245.         lstrcpy (lpCurrInc->szSpecName, "All Files");
  246.         lstrcpy (lpCurrInc->szFileSpec, "*.*");
  247.         lpCurrInc->usIncFlags = _A_RDONLY | _A_ARCH | _A_HIDDEN | _A_SYSTEM;
  248.         lpCurrInc->fScrnFlags = SCRN_INCEMPTYDIRS;
  249.     }    
  250.     // Create main window
  251.     hMain = CreateWindow (szAppName, szTitleText, WS_OVERLAPPEDWINDOW,
  252.                           x, y, cx, cy, NULL, NULL, hInstance, NULL);
  253.     if(!hMain) return 0x10;
  254.  
  255.     //Create status bar
  256.     sField[0] = 0;
  257.     sField[1] = 195;
  258.     x = StatusBarCreate (hMain, 2, sField);
  259.     if (x) return x;
  260.     
  261.     ShowWindow(hMain, nCmdShow | SW_SHOW);
  262.     UpdateWindow(hMain);              // force WM_PAINT message
  263.     return 0;                         // return success flag
  264. }
  265. //------------------------------------------------------------
  266. // TermInstance - Instance termination code for this app.
  267. //------------------------------------------------------------
  268. INT TermInstance(HANDLE hinstance, int sDefRC) {
  269.     INT i;
  270.  
  271.     if (hMasterSeg)
  272.             GlobalFree (hMasterSeg);
  273.             
  274.     for (i = 0; i < SORTTYPES; i++)
  275.         if (hSortSeg[i])
  276.             GlobalFree (hSortSeg[i]);
  277.     return sDefRC;
  278. }
  279. //============================================================
  280. // Message handling procedures for MainWindow
  281. //============================================================
  282. //------------------------------------------------------------
  283. // MainWndProc - Callback function for application window
  284. //------------------------------------------------------------
  285. LONG CALLBACK MainWndProc(HWND hWnd, UINT wMsg, UINT wParam, 
  286.                           LONG lParam) {
  287.     INT i;
  288.     //
  289.     // Search message list to see if we need to handle this
  290.     // message.  If in list, call procedure.
  291.     //
  292.     for(i = 0; i < dim(MainMessages); i++) {
  293.         if(wMsg == MainMessages[i].Code)
  294.             return (*MainMessages[i].Fxn)(hWnd, wMsg, wParam, lParam);
  295.     }
  296.     return DefWindowProc(hWnd, wMsg, wParam, lParam);
  297. }
  298. //------------------------------------------------------------
  299. // DoCreateMain - process WM_CREATE message for frame window.
  300. //------------------------------------------------------------ 
  301. LONG DoCreateMain (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  302.    RECT rect;
  303.     HWND hWndLB;
  304.  
  305.     GetFListPos (hWnd, &rect);
  306.     hWndLB = CreateWindow ("listbox", NULL, WS_CHILD | WS_VISIBLE | 
  307.                   WS_BORDER | LBS_NOTIFY | LBS_OWNERDRAWFIXED | 
  308.                   LBS_MULTIPLESEL | LBS_EXTENDEDSEL,
  309.                   rect.left, rect.top, rect.right, rect.bottom, 
  310.                   hWnd, IDD_FLIST, hInst, NULL);
  311.     //Subclass listbox to virtualize large box.                      
  312.     lpfnOldLBoxWndProc = MySubClassWindow (GetDlgItem (hWnd, IDD_FLIST),
  313.                             MakeProcInstance ((FARPROC) LBoxSCProc, hInst));
  314.     SetWindowLong (hWndLB, GWL_STYLE, 
  315.                    GetWindowLong (hWndLB, GWL_STYLE) | WS_VSCROLL);
  316.     SetScrollPos (GetDlgItem (hWnd, IDD_FLIST), SB_VERT, 0, TRUE);
  317.     return 0;
  318. }
  319. //------------------------------------------------------------
  320. // DoSizeMain - process WM_SIZE message for frame window.
  321. //------------------------------------------------------------ 
  322. LONG DoSizeMain (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  323.    RECT rect, rectList;
  324.     INT sTop;
  325.  
  326.     if (wParam != SIZE_MINIMIZED) {
  327.         GetFListPos (hWnd, &rect);
  328.         SetWindowPos (GetDlgItem (hWnd, IDD_FLIST), NULL, rect.left, rect.top, 
  329.                       rect.right, rect.bottom, SWP_NOZORDER);
  330.         // Get size of listbox to determine the number of items visible 
  331.         // in the list box.
  332.         GetClientRect (GetDlgItem (hWnd, IDD_FLIST), &rectList);
  333.         if (sLItemHeight)
  334.             sListSize = (rectList.bottom - rectList.top)/sLItemHeight;
  335.  
  336.         sTop = (INT) SendDlgItemMessage (hWnd, IDD_FLIST, LB_GETITEMDATA, 0, 0);
  337.         if ((UINT) sTop > (UINT) sCount)
  338.             sTop = 0;
  339.         FillLB (hWnd, sTop);
  340.         DisplayCurrStatus (hWnd);
  341.         if (fFirst) {
  342.             fFirst = FALSE;
  343.             PostMessage (hWnd, WM_COMMAND, IDM_REFRESH, 0);
  344.         }
  345.     }    
  346.     return 0;
  347. }
  348. //------------------------------------------------------------
  349. // DoSetFocusMain - process WM_SETFOCUS message for frame window.
  350. //------------------------------------------------------------ 
  351. LONG DoSetFocusMain (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  352.  
  353.     SetFocus (GetDlgItem (hWnd, IDD_FLIST));
  354.     return 0;
  355. }
  356. //------------------------------------------------------------
  357. // DoMeasureItemMain - process WM_MEASUREITEM message for frame window.
  358. //------------------------------------------------------------ 
  359. LONG DoMeasureItemMain (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  360.  
  361.     ((LPMEASUREITEMSTRUCT) lParam)->itemHeight = sLItemHeight;
  362.     return 0;
  363. }
  364. //------------------------------------------------------------
  365. // DoDrawItemMain - process WM_DRAWITEM message for frame 
  366. // window.  This routine handles drawing of the list box
  367. // items.
  368. //------------------------------------------------------------ 
  369. LONG DoDrawItemMain (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  370.     LPDRAWITEMSTRUCT lpdiPtr;
  371.     LPMYDIRENTRY lpDrawEnt;
  372.     LPLPMYDIRENTRY lpIndexPtr;
  373.     char szOut[256], szTemp[33];
  374.     char *pszOut;
  375.     RECT rectOut;
  376.     HANDLE hBrush;
  377.     INT i, sNumLen;
  378.     HPEN hPen, hOldPen;
  379.     
  380.     if (fSearching)
  381.         return FALSE;
  382.     if (hSortSeg[sSortIndex] == 0)
  383.         return FALSE;
  384.  
  385.     lpdiPtr = (LPDRAWITEMSTRUCT) lParam;
  386.     if ((UINT)lpdiPtr->itemData > (UINT)sCount)
  387.         return 0;
  388.         
  389.     if (lpdiPtr->itemState & ODS_SELECTED) {
  390.         SetTextColor (lpdiPtr->hDC, GetSysColor (COLOR_HIGHLIGHTTEXT));
  391.         SetBkColor (lpdiPtr->hDC, GetSysColor (COLOR_HIGHLIGHT));
  392.         hBrush = CreateSolidBrush (GetSysColor (COLOR_HIGHLIGHT));
  393.     } else {    
  394.         SetTextColor (lpdiPtr->hDC, GetSysColor (COLOR_WINDOWTEXT));
  395.         SetBkColor (lpdiPtr->hDC, GetSysColor (COLOR_WINDOW));
  396.         hBrush = CreateSolidBrush (GetSysColor (COLOR_WINDOW));
  397.     }
  398.     rectOut = lpdiPtr->rcItem;
  399.     FillRect (lpdiPtr->hDC, &rectOut, hBrush);
  400.     DeleteObject (hBrush);
  401.     rectOut.right = lpdiPtr->rcItem.left + 135;
  402.     rectOut.bottom = lpdiPtr->rcItem.bottom;
  403.  
  404.     lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hSortSeg[sSortIndex]);
  405.     
  406.     lpIndexPtr += (INT)lpdiPtr->itemData;
  407.     lpDrawEnt = *lpIndexPtr;
  408.  
  409.     // Display file name
  410.     if (lpDrawEnt->ucAttrib & _A_SUBDIR) {
  411.         szOut[0] = '[';
  412.         lstrcpy (&szOut[1], lpDrawEnt->szName);
  413.         strcat (szOut, "]");
  414.     } else    
  415.         lstrcpy (szOut, lpDrawEnt->szName);
  416.     pszOut = szOut;        
  417.     while (*pszOut == ' ')
  418.         pszOut++;
  419.     DrawText (lpdiPtr->hDC, pszOut, -1, &rectOut, DT_LEFT | DT_SINGLELINE); 
  420.  
  421.     // Display file size
  422.     if (fViewFlags & SHOW_SIZE) {
  423.         ltoa (lpDrawEnt->lSize, szTemp, 10);
  424.         sNumLen = strlen (szTemp);
  425.         pszOut = szOut;
  426.         for (i = 0; i < sNumLen; i++) {
  427.             if ((sNumLen - i) % 3 == 0 && i != 0)
  428.                 *pszOut++ = ',';
  429.             *pszOut++ = szTemp[i];
  430.         }
  431.         *pszOut = '\0';
  432.         rectOut.left = rectOut.right;
  433.         rectOut.right += 90;
  434.         DrawText (lpdiPtr->hDC, szOut, -1, &rectOut,    DT_RIGHT | DT_SINGLELINE); 
  435.         rectOut.right += 15;
  436.     }    
  437.  
  438.     // Display date
  439.     if (fViewFlags & SHOW_DATE) {
  440.         rectOut.left = rectOut.right;
  441.         rectOut.right += 160;
  442.         Date2asc (lpDrawEnt->usDate, lpDrawEnt->usTime, szOut);
  443.         DrawText (lpdiPtr->hDC, szOut, -1, &rectOut, DT_LEFT | DT_SINGLELINE); 
  444.     }
  445.  
  446.     // Display attributes
  447.     if (fViewFlags & SHOW_ATTRIB) {
  448.         rectOut.left = rectOut.right;
  449.         rectOut.right += 50;
  450.         Attr2asc (lpDrawEnt->ucAttrib, szOut);
  451.         DrawText (lpdiPtr->hDC, szOut, -1, &rectOut, DT_LEFT | DT_SINGLELINE); 
  452.     }
  453.  
  454.     // Display complete path
  455.     if (fViewFlags & SHOW_PATH) {
  456.         if (lpDrawEnt->lpParent) {
  457.         i = sizeof (szOut);
  458.             szOut[0] = '\0';
  459.             CreatePath (lpDrawEnt, szOut, &i);
  460.         } else {
  461.             lstrcpy (szOut, lpDrawEnt->szName);
  462.         }                    
  463.         rectOut.left = rectOut.right;
  464.         rectOut.right += 500;
  465.         pszOut = szOut;        
  466.         while (*pszOut == ' ')
  467.             pszOut++;
  468.         DrawText (lpdiPtr->hDC, pszOut, -1, &rectOut, DT_LEFT | DT_SINGLELINE); 
  469.     }
  470.     GlobalUnlock (hSortSeg[sSortIndex]);
  471.  
  472.     if (lpdiPtr->itemState & ODS_FOCUS) {
  473.         if (lpdiPtr->itemState & ODS_SELECTED)
  474.             hPen = CreatePen (PS_DOT, 1, GetSysColor (COLOR_HIGHLIGHTTEXT));
  475.         else    
  476.             hPen = CreatePen (PS_DOT, 1, GetSysColor (COLOR_WINDOWTEXT));
  477.         hOldPen = SelectObject (lpdiPtr->hDC, hPen);
  478.         MoveTo (lpdiPtr->hDC, lpdiPtr->rcItem.left, lpdiPtr->rcItem.bottom-1);
  479.         LineTo (lpdiPtr->hDC, lpdiPtr->rcItem.left, lpdiPtr->rcItem.top);
  480.         LineTo (lpdiPtr->hDC, lpdiPtr->rcItem.right-1, lpdiPtr->rcItem.top);
  481.         LineTo (lpdiPtr->hDC, lpdiPtr->rcItem.right-1, lpdiPtr->rcItem.bottom-1);
  482.         LineTo (lpdiPtr->hDC, lpdiPtr->rcItem.left, lpdiPtr->rcItem.bottom-1);
  483.         SelectObject (lpdiPtr->hDC, hOldPen);
  484.         DeleteObject (hPen);
  485.     }    
  486.     return 0;
  487. }
  488. //------------------------------------------------------------
  489. // DoInitMenuMain - process WM_INITMENU message for frame window.
  490. //------------------------------------------------------------ 
  491. LONG DoInitMenuMain (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  492.     INT i;
  493.     HMENU hMenu;
  494.  
  495.     //Check menu item of active sort type
  496.     for (i = 0; i < SORTTYPES; i++)
  497.         if (i == sSortIndex)
  498.             CheckMenuItem ((HMENU) wParam, IDM_SORTNAME + i, MF_BYCOMMAND | MF_CHECKED);
  499.         else
  500.             CheckMenuItem ((HMENU) wParam, IDM_SORTNAME + i, MF_BYCOMMAND | MF_UNCHECKED);
  501.     //Check the viewing selection items size, date, attrib and path
  502.     if (fViewFlags & SHOW_SIZE)
  503.         CheckMenuItem ((HMENU) wParam, IDM_SHOWSIZE, MF_BYCOMMAND | MF_CHECKED);
  504.     else    
  505.         CheckMenuItem ((HMENU) wParam, IDM_SHOWSIZE, MF_BYCOMMAND | MF_UNCHECKED);
  506.  
  507.     if (fViewFlags & SHOW_DATE)
  508.         CheckMenuItem ((HMENU) wParam, IDM_SHOWDATE, MF_BYCOMMAND | MF_CHECKED);
  509.     else    
  510.         CheckMenuItem ((HMENU) wParam, IDM_SHOWDATE, MF_BYCOMMAND | MF_UNCHECKED);
  511.  
  512.     if (fViewFlags & SHOW_ATTRIB)
  513.         CheckMenuItem ((HMENU) wParam, IDM_SHOWATTRIB, MF_BYCOMMAND | MF_CHECKED);
  514.     else    
  515.         CheckMenuItem ((HMENU) wParam, IDM_SHOWATTRIB, MF_BYCOMMAND | MF_UNCHECKED);
  516.  
  517.     if (fViewFlags & SHOW_PATH)
  518.         CheckMenuItem ((HMENU) wParam, IDM_SHOWPATH, MF_BYCOMMAND | MF_CHECKED);
  519.     else    
  520.         CheckMenuItem ((HMENU) wParam, IDM_SHOWPATH, MF_BYCOMMAND | MF_UNCHECKED);
  521.     //Get menu for include set    
  522.     if (sOldIncCnt != sIncCount) {
  523.         hMenu = GetSubMenu (GetMenu (hWnd), MENU_INCLUDE);
  524.         for (i = 1; i < 8; i++)
  525.             if (!DeleteMenu (hMenu, IDM_INCLUDEALL + i, MF_BYCOMMAND))
  526.                 break;
  527.             
  528.         for (i = 1; i < sIncCount; i++)
  529.             AppendMenu (hMenu, MF_ENABLED, IDM_INCLUDEALL + i, 
  530.                         incArray[i].szSpecName);
  531.         sOldIncCnt = sIncCount;                            
  532.     }
  533.     return 0;
  534. }
  535. //------------------------------------------------------------
  536. // DoCommandMain - process WM_COMMAND message for frame window 
  537. // by decoding the menubar item with the menuitems[] array, 
  538. // then running the corresponding function to process the command.
  539. //------------------------------------------------------------ 
  540. LONG DoCommandMain (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  541.     INT    i;
  542.     UINT    idItem, wNotifyCode;
  543.     HWND    hwndCtl;
  544.  
  545.     idItem = (UINT) wParam;                      // Parse Parameters
  546.     hwndCtl = (HWND) LOWORD(lParam);
  547.     wNotifyCode = (UINT) HIWORD(lParam);
  548.     //
  549.     // Call routine to handle control message
  550.     //
  551.     for(i = 0; i < dim(MainMenuItems); i++) {
  552.         if(idItem == MainMenuItems[i].Code)
  553.             return (*MainMenuItems[i].Fxn)(hWnd, idItem, hwndCtl, 
  554.                                            wNotifyCode);
  555.     }
  556.     return DefWindowProc(hWnd, wMsg, wParam, lParam);
  557. }
  558. //------------------------------------------------------------
  559. // DoCloseMain - process WM_CLOSE message for frame window.
  560. //------------------------------------------------------------ 
  561. LONG DoCloseMain (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  562.     fSearching = FALSE;
  563.     DestroyWindow (hMain);
  564.     return 0;
  565. }
  566. //------------------------------------------------------------
  567. // DoDestroyMain - process WM_DESTROY message for frame window.
  568. //------------------------------------------------------------ 
  569. LONG DoDestroyMain (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  570.    RECT    rect;
  571.     char szOut[40], szTemp[33];
  572.     INT i;
  573.  
  574.     fSearching = FALSE;
  575.     //Save Window position
  576.     if    (!IsIconic (hWnd) && !IsZoomed (hWnd)) {
  577.         GetWindowRect (hWnd, &rect);
  578.         MyWritePrivateProfileInt (szAppName, PRO_XPOS, rect.left,
  579.                                   10, szProfileName);
  580.         MyWritePrivateProfileInt (szAppName, PRO_YPOS, rect.top,
  581.                                   10, szProfileName);
  582.         MyWritePrivateProfileInt (szAppName, PRO_XSIZE, rect.right - rect.left,
  583.                                   10, szProfileName);
  584.         MyWritePrivateProfileInt (szAppName, PRO_YSIZE, rect.bottom - rect.top,
  585.                                   10, szProfileName);
  586.     }
  587.     //
  588.     //Write include array info
  589.     //
  590.     for (i = 1; i < MAXINCSPECS; i++) {
  591.         itoa (i, szOut, 10);
  592.         //Erase entry
  593.         WritePrivateProfileString (szOut, "", "", szProfileName);
  594.     }    
  595.     lpCurrInc = &incArray[0];
  596.     MyWritePrivateProfileInt (szAppName, PRO_INCCNT, sIncCount, 10, szProfileName);
  597.     for (i = 0; i < sIncCount; i++) {
  598.         itoa (i, szOut, 10);
  599.         WritePrivateProfileString (szOut, PRO_SPECNAME, lpCurrInc->szSpecName,
  600.                                    szProfileName);
  601.         WritePrivateProfileString (szOut, PRO_FILESPEC, lpCurrInc->szFileSpec,
  602.                                    szProfileName);
  603.         ltoa (lpCurrInc->lIncSize, szTemp, 10);
  604.         WritePrivateProfileString (szOut, PRO_INCSIZE, szTemp, szProfileName);
  605.         MyWritePrivateProfileInt (szOut, PRO_INCDATE, lpCurrInc->usIncDate,
  606.                                 10, szProfileName);
  607.         MyWritePrivateProfileInt (szOut, PRO_INCFLAGS, lpCurrInc->usIncFlags,
  608.                                 10, szProfileName);
  609.         MyWritePrivateProfileInt (szOut, PRO_SCRNFLAGS, lpCurrInc->fScrnFlags,
  610.                                   10, szProfileName);
  611.         lpCurrInc++;
  612.     }    
  613.     //Remove subclassing on listbox
  614.     MySubClassWindow (GetDlgItem (hWnd, IDD_FLIST), lpfnOldLBoxWndProc);
  615.     PostQuitMessage (0);
  616.     return DefWindowProc(hWnd, wMsg, wParam, lParam);
  617. }
  618. //============================================================
  619. // Control handling procedures for MainWindow
  620. //============================================================
  621. //------------------------------------------------------------
  622. // DoMainCtlFList - Process Listbox control messages
  623. //------------------------------------------------------------ 
  624. LONG DoMainCtlFList (HWND hWnd, UINT idItem, HWND hwndCtl, 
  625.                      UINT wNotifyCode) {
  626.     INT i, sSelCnt;
  627.     LPLPMYDIRENTRY lpIndexPtr;
  628.     
  629.     if (wNotifyCode == LBN_SELCHANGE) {
  630.         sSelCnt = (INT) SendDlgItemMessage (hWnd, IDD_FLIST, LB_GETSELCOUNT, 
  631.                                             0, 0);
  632.         if ((sSelCnt <= 1) && fSelOS) {
  633.             lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hSortSeg[sSortIndex]);
  634.             for (i = 0; i < sCount; i++) {
  635.                 (*lpIndexPtr)->ucAttrib &= ~ATTR_SELECTED;
  636.                 lpIndexPtr++;
  637.             }
  638.             fSelOS = FALSE;
  639.             GlobalUnlock (hSortSeg[sSortIndex]);
  640.         }    
  641.     }
  642.     return 0;
  643. }
  644. //------------------------------------------------------------
  645. // DoMainMenuRefresh - Process Refresh menu item
  646. //------------------------------------------------------------ 
  647. LONG DoMainMenuRefresh (HWND hWnd, UINT idItem, HWND hwndCtl, 
  648.                      UINT wNotifyCode) {
  649.     INT rc;
  650.  
  651.     MyDisplayDialog(hInst, "Refresh", hWnd, 
  652.                     (WNDPROC) RefreshDlgProc, 0);
  653.     rc = GetIncludedFiles (hWnd);
  654.     if (rc)
  655.         PrintError (hWnd, rc);
  656.     else {
  657.         FillLB (hWnd, 0);
  658.         DisplayCurrStatus (hWnd);
  659.     }    
  660.     return 0;
  661. }
  662. //------------------------------------------------------------
  663. // DoMainMenuMCD - Process Move, Copy and Delete menu items
  664. //------------------------------------------------------------ 
  665. LONG DoMainMenuMCD (HWND hWnd, UINT idItem, HWND hwndCtl, 
  666.                     UINT wNotifyCode) {
  667.     INT rc;
  668.  
  669.     if ((SendDlgItemMessage (hWnd, IDD_FLIST, LB_GETSELCOUNT, 0, 0) == 0)  && !fSelOS) {
  670.         MessageBox (hWnd, "No files selected.",
  671.                     szTitleText, MB_OK | MB_ICONHAND);
  672.         return 0;
  673.     }
  674.     if (idItem == IDM_DELETE)
  675.         rc = MyDisplayDialog(hInst, "DelFiles", hWnd, (WNDPROC) MoveCopyDelDlgProc, 
  676.                             (DWORD)idItem - IDM_COPY);
  677.     else
  678.         rc = MyDisplayDialog(hInst, "MoveCopyFiles", hWnd, 
  679.                          (WNDPROC) MoveCopyDelDlgProc, (DWORD)idItem - IDM_COPY);
  680.     if (rc == 0) {
  681.         rc = GetIncludedFiles (hWnd);
  682.         if (rc) {
  683.             PrintError (hWnd, rc);
  684.             return 0;
  685.         }        
  686.         FillLB (hWnd, 0);
  687.     }
  688.     DisplayCurrStatus (hWnd);
  689.     return 0;
  690. }
  691. //------------------------------------------------------------
  692. // DoMainMenuExit - Process Exit menu item
  693. //------------------------------------------------------------ 
  694. LONG DoMainMenuExit (HWND hWnd, UINT idItem, HWND hwndCtl, 
  695.                      UINT wNotifyCode) {
  696.  
  697.     SendMessage (hWnd, WM_CLOSE, 0, 0);
  698.     return 0;
  699. }
  700. //------------------------------------------------------------
  701. // DoMainMenuFind - Process Find, Find Next and Find Prev menu items.
  702. //------------------------------------------------------------ 
  703. LONG DoMainMenuFind (HWND hWnd, UINT idItem, HWND hwndCtl, 
  704.                         UINT wNotifyCode) {
  705.     static INCSPEC incData;
  706.     LPLPMYDIRENTRY lpIndexPtr;
  707.     INT sStart, i;
  708.     BOOL fFound = FALSE;
  709.  
  710.     if ((idItem == IDM_FIND) || fFindNew) {
  711.         memset (&incData, 0, sizeof (incData));
  712.         lstrcpy (incData.szFileSpec, "*.*");
  713.         incData.usIncDate = 0x21;
  714.         incData.fScrnFlags = 1 | DLG_FIND;
  715.         i = MyDisplayDialog(hInst, "FindFile", hWnd, (WNDPROC) IncFilesDlgProc, 
  716.                             (DWORD)(LPVOID)&incData);
  717.         if (i == 0)
  718.             return 0;
  719.     }
  720.  
  721.     lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hSortSeg[sSortIndex]);
  722.     if (lpIndexPtr == 0)
  723.         return 0;
  724.     sStart = (INT) SendDlgItemMessage (hWnd, IDD_FLIST, LB_GETCARETINDEX, 0, 0);
  725.     if (sStart == LB_ERR)
  726.         sStart = 0;
  727.     sStart = (INT) SendDlgItemMessage (hWnd, IDD_FLIST, LB_GETITEMDATA, 
  728.                                                sStart, 0);
  729.     if (idItem == IDM_FINDPREV) {
  730.         for (i = max (sStart-1, 0); (i >= 0) && !fFound; i--) {
  731.             fFound = ScreenFile (*(lpIndexPtr + i), &incData);
  732.         }
  733.         i++;
  734.     } else {
  735.         for (i = sStart; (i < sCount) && !fFound; i++) {
  736.             fFound = ScreenFile (*(lpIndexPtr + i), &incData);
  737.             if ((fFound) && (i == sStart) && !fFindNew)
  738.                 fFound = FALSE;
  739.         }
  740.         i--;
  741.     }
  742.     if (fFound) {
  743.         i = max (i - 3, 0);
  744.         FillLB (hWnd, i);
  745.         SendDlgItemMessage (hWnd, IDD_FLIST, LB_SETSEL, TRUE, min (3, i));
  746.         SetStatusBarText (hWnd, "File Found", 0);
  747.     } else    
  748.         SetStatusBarText (hWnd, "No Files Found", 0);
  749.     GlobalUnlock (hSortSeg[sSortIndex]);
  750.     fFindNew = FALSE;
  751.     return 0;
  752. }                                
  753. //------------------------------------------------------------
  754. // DoMainMenuInvert - Process Sort Assending/descending menu
  755. // items.
  756. //------------------------------------------------------------ 
  757. LONG DoMainMenuInvert (HWND hWnd, UINT idItem, HWND hwndCtl, 
  758.                         UINT wNotifyCode) {
  759.     HMENU hMenu;
  760.     INT i;
  761.     
  762.     hMenu = GetSubMenu (GetMenu (hWnd), MENU_VIEW);
  763.     if (fSortUp)
  764.         fSortUp = FALSE;
  765.     else
  766.         fSortUp = TRUE;
  767.     // Invert the index arrays        
  768.     if (!hMasterSeg)
  769.         return 0;
  770.     for (i = 0; i < SORTTYPES; i++)
  771.         if (hSortSeg[i]) {
  772.             InvertIndex ((HPDWORD)GlobalLock (hSortSeg[i]), sCount);
  773.             GlobalUnlock (hSortSeg[i]);
  774.         }    
  775.     FillLB (hWnd, 0);
  776.     DisplayCurrStatus (hWnd);
  777.     return 0;
  778. }                                
  779. //------------------------------------------------------------
  780. // DoMainMenuShow - Process Show Attrib, Show Size ect. menu 
  781. // items.
  782. //------------------------------------------------------------ 
  783. LONG DoMainMenuShow (HWND hWnd, UINT idItem, HWND hwndCtl, 
  784.                         UINT wNotifyCode) {
  785.     UINT usIndex;
  786.     HMENU hMenu;
  787.     
  788.     hMenu = GetSubMenu (GetMenu (hWnd), MENU_VIEW);
  789.     usIndex = idItem - IDM_SHOWSIZE;
  790.     if (GetMenuState (hMenu, idItem, MF_BYCOMMAND) == MF_CHECKED) 
  791.         fViewFlags &= ~(1 << usIndex);
  792.     else
  793.         fViewFlags |= (1 << usIndex);
  794.  
  795.     InvalidateRect (hWnd, NULL, FALSE);
  796.     return 0;
  797. }                                
  798. //------------------------------------------------------------
  799. // DoMainMenuSort - Process Sort by... menu items.
  800. //------------------------------------------------------------ 
  801. LONG DoMainMenuSort (HWND hWnd, UINT idItem, HWND hwndCtl, 
  802.                         UINT wNotifyCode) {
  803.     INT i, sIndex, rc;
  804.     HPDWORD lpDest, lpSrc;
  805.     LPLPMYDIRENTRY lpIndexPtr;
  806.  
  807.     sIndex = idItem - IDM_SORTNAME;
  808.     if (sCount == 0)
  809.         return 0;
  810.     if (hSortSeg[sIndex] == 0) {
  811.         hSortSeg[sIndex] = GlobalAlloc (GHND, (LONG)sCount * sizeof (LPMYDIRENTRY));
  812.         if (hSortSeg[sIndex] == 0) {
  813.             PrintError (hWnd, ERR_OUTOFMEM);
  814.             return 0;
  815.         }
  816.         SetStatusBarText (hWnd, "Sorting...", 0);
  817.         lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hSortSeg[sIndex]);
  818.         
  819.         lpDest = (HPDWORD) lpIndexPtr;
  820.         lpSrc = (HPDWORD) GlobalLock (hSortSeg[sSortIndex]);
  821.         for (i = 0; i < sCount; i++)
  822.             *lpDest++ = *lpSrc++;        
  823.         GlobalUnlock (hSortSeg[sSortIndex]);
  824.         rc = MyQSort (lpIndexPtr, sCount, (PSORTFUNC) pSortFunc[sIndex]);
  825.         if (rc)
  826.             PrintError (hWnd, rc);
  827.         DisplayCurrStatus (hWnd);
  828.         GlobalUnlock (hSortSeg[sIndex]);
  829.     }    
  830.     FillLB (hWnd, 0);
  831.     sSortIndex = sIndex;
  832.     DisplayCurrStatus (hWnd);
  833.     InvalidateRect (hWnd, NULL, FALSE);
  834.     return 0;
  835. }                                
  836. //------------------------------------------------------------
  837. // DoMainMenuInclude - Process Include|Define Include Set menu item
  838. //------------------------------------------------------------ 
  839. LONG DoMainMenuInclude (HWND hWnd, UINT idItem, HWND hwndCtl, 
  840.                         UINT wNotifyCode) {
  841.     INCSPEC incData;
  842.  
  843.     memset (&incData, 0, sizeof (incData));
  844.     lstrcpy (incData.szFileSpec, "*.*");
  845.     incData.usIncFlags = _A_RDONLY |    _A_ARCH | _A_HIDDEN | _A_SYSTEM;
  846.     incData.usIncDate = 0x21;
  847.     incData.fScrnFlags = 1 | DLG_INCLUDE;
  848.  
  849.     if (MyDisplayDialog(hInst, "IncFiles", hWnd, 
  850.                         (WNDPROC) IncFilesDlgProc, (DWORD)(LPVOID)&incData)) {
  851.  
  852.         incData.fScrnFlags &= ~DLG_INCLUDE;
  853.         AddIncSet (hWnd, &incData);
  854.     }        
  855.     return 0;
  856. }
  857. //------------------------------------------------------------
  858. // DoMainMenuIncludeEdit - Process Include|Edit Include Set menu item
  859. //------------------------------------------------------------ 
  860. LONG DoMainMenuIncludeEdit (HWND hWnd, UINT idItem, HWND hwndCtl, 
  861.                             UINT wNotifyCode) {
  862.     INCSPEC incData;
  863.     INT rc, sEditItem;
  864.     BOOL fReset = FALSE;
  865.  
  866.     if (sIncCount <= 1) {
  867.         MessageBox (hWnd, "The \'All Files\' Query can not be edited.",
  868.                     szTitleText, MB_OK | MB_ICONHAND);
  869.         return 0;
  870.     }
  871.     sEditItem = MyDisplayDialog(hInst, "IncludeDel", hWnd, 
  872.                                 (WNDPROC) IncludeDelDlgProc, 1);
  873.     if (sEditItem == 0)
  874.         return 0;                                         
  875.  
  876.     incData = incArray[sEditItem];
  877.     incData.fScrnFlags |= DLG_INCLUDEEDIT;
  878.  
  879.     rc = MyDisplayDialog (hInst, "IncFiles", hWnd, (WNDPROC)IncFilesDlgProc, 
  880.                           (DWORD)(LPVOID)&incData);
  881.     if (rc == 0)
  882.         return 0;
  883.  
  884.     incData.fScrnFlags &= ~DLG_INCLUDEEDIT;
  885.     sOldIncCnt = 0;    //Force menu regen on next menu init.
  886.     
  887.     if (rc == 2)
  888.         AddIncSet (hWnd, &incData);
  889.     else {
  890.         incArray[sEditItem] = incData;
  891.  
  892.         lpCurrInc = &incArray[sEditItem];
  893.         rc = GetIncludedFiles (hWnd);
  894.         if (rc) {
  895.             PrintError (hWnd, rc);
  896.             return 0;
  897.         }        
  898.         FillLB (hWnd, 0);
  899.         DisplayCurrStatus (hWnd);
  900.     }        
  901.     return 0;
  902. }
  903. //------------------------------------------------------------
  904. // DoMainMenuIncludeDel - Process Include|Del Include Set menu item
  905. //------------------------------------------------------------ 
  906. LONG DoMainMenuIncludeDel (HWND hWnd, UINT idItem, HWND hwndCtl, 
  907.                            UINT wNotifyCode) {
  908.     INT i, rc, sDelItem;
  909.     BOOL fReset = FALSE;
  910.  
  911.     if (sIncCount <= 1) {
  912.         MessageBox (hWnd, "The \'All Files\' Query can not be deleted.",
  913.                     szTitleText, MB_OK | MB_ICONHAND);
  914.         return 0;
  915.     }
  916.     sDelItem = MyDisplayDialog(hInst, "IncludeDel", hWnd, 
  917.                                 (WNDPROC) IncludeDelDlgProc, 0);
  918.     if (sDelItem == 0)
  919.         return 0;                                         
  920.     // If deleting current inc set, make all files current set    
  921.     if (lpCurrInc == &incArray[sDelItem]) {
  922.         lpCurrInc = incArray;
  923.         fReset = TRUE;
  924.     } else if (lpCurrInc > &incArray[sDelItem]) 
  925.         lpCurrInc--;
  926.  
  927.     //Delete item by overwriting others on top of it.
  928.     for (i = sDelItem; i < sIncCount; i++)
  929.         incArray[i] = incArray[i+1];
  930.     sIncCount--;
  931.  
  932.     if (fReset) {                        
  933.         rc = GetIncludedFiles (hWnd);
  934.         if (rc) {
  935.             PrintError (hWnd, rc);
  936.             return 0;
  937.         }        
  938.         FillLB (hWnd, 0);
  939.         DisplayCurrStatus (hWnd);
  940.     }        
  941.     return 0;
  942. }
  943. //------------------------------------------------------------
  944. // DoMainMenuIncludeSet - Process Include set menu items
  945. //------------------------------------------------------------ 
  946. LONG DoMainMenuIncludeSet (HWND hWnd, UINT idItem, HWND hwndCtl, 
  947.                         UINT wNotifyCode) {
  948.     UINT i;
  949.     INT rc;
  950.  
  951.     i = idItem - IDM_INCLUDEALL;
  952.     lpCurrInc = &incArray[i];
  953.  
  954.     //Get include set
  955.     rc = GetIncludedFiles (hWnd);
  956.     if (rc) {
  957.         PrintError (hWnd, rc);
  958.         return 0;
  959.     }        
  960.     FillLB (hWnd, 0);
  961.     DisplayCurrStatus (hWnd);
  962.     return 0;
  963. }
  964. //------------------------------------------------------------
  965. // DoMainMenuAbout - Process About button
  966. //------------------------------------------------------------ 
  967. LONG DoMainMenuAbout (HWND hWnd, UINT idItem, HWND hwndCtl, 
  968.                      UINT wNotifyCode) {
  969.                                 
  970.     MyDisplayDialog(hInst, "AboutBox", hWnd, 
  971.                     (WNDPROC) AboutDlgProc, (LONG) wVersion);
  972.     return 0;
  973. }
  974. //============================================================
  975. // Virtual list box routines 
  976. //
  977. //  The virtual list box designed here is incomplete, since
  978. // it depends on the index to store its data pointer 
  979. // and on the file data structures to store the a 
  980. // 'selected flag' for an item when it is not displayed
  981. // in the listbox.  Also, such niceties as the 
  982. // LBS_WANTKEYBOARDINPUT style are not supported. 
  983. //============================================================
  984. //------------------------------------------------------------
  985. // ScrollVLBDown - Scroll the virtual list box down one item
  986. //------------------------------------------------------------ 
  987. INT ScrollVLBDown (HWND hWnd, INT sSCnt, BOOL fSelected) {
  988.     INT i, sIndex, sIndexBot;
  989.     LPLPMYDIRENTRY lpIndexPtr;
  990.     LPMYDIRENTRY lpEntry;
  991.  
  992.     lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hSortSeg[sSortIndex]);
  993.     for (i = 0; i < sSCnt; i++) {
  994.         //If at end of list, return    
  995.         //Check item about to be scrolled off the top of the list.
  996.         //If selected, mark.
  997.         sIndexBot = (INT) SendMessage (hWnd, LB_GETITEMDATA, sListSize-1, 0);
  998.         sIndex = (INT) SendMessage (hWnd, LB_GETITEMDATA, 0, 0);
  999.         if ((sIndexBot == LB_ERR) || (sIndexBot >= sCount - 1) || (sIndex == LB_ERR))
  1000.             break;
  1001.         
  1002.         lpEntry = *(lpIndexPtr + sIndex);
  1003.         if (SendMessage (hWnd, LB_GETSEL, 0, 0)) {
  1004.             lpEntry->ucAttrib |= ATTR_SELECTED;
  1005.             fSelOS = TRUE;
  1006.         } else
  1007.             lpEntry->ucAttrib &= ~ATTR_SELECTED;
  1008.         //Turn off redraw add new item at bottom, delete top item
  1009.         SendMessage (hWnd, LB_DELETESTRING, 0, 0);
  1010.         sIndex = (INT) SendMessage (hWnd, LB_INSERTSTRING, -1, sIndexBot+1);
  1011.         lpEntry = *(lpIndexPtr + sIndexBot + 1);
  1012.         if ((lpEntry->ucAttrib & ATTR_SELECTED) || fSelected)
  1013.             SendMessage (hWnd, LB_SETSEL, TRUE, sIndex);
  1014.  
  1015.  
  1016.  
  1017.     }
  1018.     GlobalUnlock (hSortSeg[sSortIndex]);
  1019.     return i;
  1020. }    
  1021. //------------------------------------------------------------
  1022. // ScrollVLBUp - Scroll the virtual list box up one item
  1023. //------------------------------------------------------------ 
  1024. INT ScrollVLBUp (HWND hWnd, INT sSCnt, BOOL fSelected) {
  1025.     INT i, sIndex, sIndexTop;
  1026.     LPLPMYDIRENTRY lpIndexPtr;
  1027.     LPMYDIRENTRY lpEntry;
  1028.  
  1029.     lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hSortSeg[sSortIndex]);
  1030.     for (i = 0; i < sSCnt; i++) {
  1031.         //Check item about to be scrolled off the bottom of the list.
  1032.         //If selected, mark.
  1033.         sIndexTop = (INT) SendMessage (hWnd, LB_GETITEMDATA, 0, 0);
  1034.         sIndex = (INT) SendMessage (hWnd, LB_GETITEMDATA, sListSize-1, 0);
  1035.         if ((sIndexTop == LB_ERR) || (sIndexTop == 0))
  1036.             break;
  1037.     
  1038.         //Turn off redraw add new item at top, delete bottom item
  1039.         if ((sIndex != LB_ERR) && (sIndex < sCount)) {
  1040.             lpEntry = *(lpIndexPtr + sIndex);
  1041.             if (SendMessage (hWnd, LB_GETSEL, sListSize-1, 0)) {
  1042.                 lpEntry->ucAttrib |= ATTR_SELECTED;
  1043.                 fSelOS = TRUE;
  1044.             } else
  1045.                 lpEntry->ucAttrib &= ~ATTR_SELECTED;
  1046.             SendMessage (hWnd, LB_DELETESTRING, sListSize-1, 0);
  1047.         }            
  1048.         sIndex = (INT) SendMessage (hWnd, LB_INSERTSTRING, 0, sIndexTop - 1);
  1049.         lpEntry = *(lpIndexPtr + sIndexTop - 1);
  1050.         if ((lpEntry->ucAttrib & ATTR_SELECTED) || fSelected)
  1051.             SendMessage (hWnd, LB_SETSEL, TRUE, sIndex);
  1052.         SendMessage (hWnd, LB_SETTOPINDEX, 0, 0);
  1053.     }    
  1054.     GlobalUnlock (hSortSeg[sSortIndex]);
  1055.     return i;
  1056. }    
  1057. //------------------------------------------------------------
  1058. // MoveVLB - Moves the top index of the listbox
  1059. //------------------------------------------------------------ 
  1060. INT MoveVLB (HWND hWnd, INT sPos) {
  1061.     INT i, sIndex;
  1062.     LPLPMYDIRENTRY lpIndexPtr;
  1063.     LPMYDIRENTRY lpEntry;
  1064.  
  1065.     lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hSortSeg[sSortIndex]);
  1066.     SendMessage (hWnd, WM_SETREDRAW, FALSE, 0);
  1067.     sIndex = (INT) SendMessage (hWnd, LB_GETITEMDATA, 0, 0);
  1068.     if (sIndex == LB_ERR) 
  1069.         return 0;
  1070.     for (i = 0; i < sListSize; i++) {
  1071.         lpEntry = *(lpIndexPtr + sIndex + i);
  1072.         if (SendMessage (hWnd, LB_GETSEL, i, 0)) {
  1073.             lpEntry->ucAttrib |= ATTR_SELECTED;
  1074.             fSelOS = TRUE;
  1075.         } else
  1076.             lpEntry->ucAttrib &= ~ATTR_SELECTED;
  1077.     }
  1078.     GlobalUnlock (hSortSeg[sSortIndex]);
  1079.     SendMessage (hWnd, LB_RESETCONTENT, 0, 0);
  1080.     for (i = sPos; (i < sPos + sListSize) && (i < sCount); i++)  {
  1081.         sIndex = (INT)SendMessage (hWnd, LB_ADDSTRING, 0, (LPARAM) (LONG) i);
  1082.         lpEntry = *(lpIndexPtr + i);
  1083.         if (lpEntry->ucAttrib & ATTR_SELECTED) 
  1084.             SendMessage (hWnd, LB_SETSEL, sIndex, 0);
  1085.     }
  1086.     SetScrollRange (hWnd, SB_VERT, 0, sCount - sListSize, FALSE);
  1087.     SendMessage (hWnd, WM_SETREDRAW, TRUE, 0);
  1088.     return 0;
  1089. }    
  1090. //------------------------------------------------------------
  1091. // ClearSelVLB - Unselects all items.
  1092. //------------------------------------------------------------ 
  1093. void ClearSelVLB (HWND hWnd) {
  1094.     INT i;
  1095.     LPLPMYDIRENTRY lpIndexPtr;
  1096.  
  1097.     SendMessage (hWnd, LB_SETSEL, FALSE, MAKELONG (-1, 0));
  1098.     if (fSelOS) {
  1099.         lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hSortSeg[sSortIndex]);
  1100.         for (i = 0; i < sCount; i++) {
  1101.             (*lpIndexPtr)->ucAttrib &= ~ATTR_SELECTED;
  1102.             lpIndexPtr++;
  1103.         }
  1104.         fSelOS = FALSE;
  1105.         GlobalUnlock (hSortSeg[sSortIndex]);
  1106.     }    
  1107.     return;
  1108. }
  1109. //============================================================
  1110. // LBoxSCProc - Subclass procedure for Listbox
  1111. //============================================================
  1112. LONG CALLBACK LBoxSCProc (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  1113.     INT i, sScrollPos, sCaretIndex;
  1114.     BOOL fShift;
  1115.  
  1116.     switch (wMsg) {
  1117.         case WM_VSCROLL:
  1118.             
  1119.             sScrollPos = GetScrollPos (hWnd, SB_VERT); 
  1120.             switch (wParam) {
  1121.                 case SB_BOTTOM:
  1122.                     sScrollPos = sCount - sListSize;
  1123.                     break;
  1124.                     
  1125.                 case SB_TOP:
  1126.                     sScrollPos = 0;
  1127.                     break;
  1128.                     
  1129.                 case SB_LINEDOWN:
  1130.                     sScrollPos += ScrollVLBDown (hWnd, 1, FALSE);
  1131.                     break;
  1132.                     
  1133.                 case SB_LINEUP:
  1134.                     sScrollPos -= ScrollVLBUp (hWnd, 1, FALSE);
  1135.                     break;
  1136.                     
  1137.                 case SB_PAGEDOWN:
  1138.                      sScrollPos += ScrollVLBDown (hWnd, sListSize - 1, FALSE);
  1139.                       break;
  1140.                     
  1141.                 case SB_PAGEUP:
  1142.                     sScrollPos -= ScrollVLBUp (hWnd, sListSize - 1, FALSE);
  1143.                     break;
  1144.                     
  1145.                 case SB_THUMBPOSITION:
  1146.                 case SB_THUMBTRACK:
  1147.                     i = (INT) LOWORD (lParam) - sScrollPos;
  1148.                     if (i > sListSize) 
  1149.                         MoveVLB (hWnd, LOWORD (lParam));
  1150.                     else if (i < 0)
  1151.                         sScrollPos -= ScrollVLBUp (hWnd, -i, FALSE);
  1152.                     else 
  1153.                         sScrollPos += ScrollVLBDown (hWnd, i, FALSE);
  1154.                     sScrollPos = LOWORD (lParam);
  1155.                     break;
  1156.             }
  1157.             SetScrollPos (hWnd, SB_VERT, sScrollPos, TRUE); 
  1158.             return 0;
  1159.             
  1160.         case WM_LBUTTONDOWN:
  1161.             if (!(GetKeyState (VK_CONTROL) & 0x8000) &&
  1162.                 !(GetKeyState (VK_SHIFT) & 0x8000)) 
  1163.                 ClearSelVLB (hWnd);
  1164.             break;                
  1165.  
  1166.         case WM_KEYDOWN:
  1167.             sScrollPos = GetScrollPos (hWnd, SB_VERT); 
  1168.             sCaretIndex = (INT) SendMessage (hWnd, LB_GETCARETINDEX, 0, 0);
  1169.             fShift = GetKeyState (VK_SHIFT) & 0x8000;
  1170.                 
  1171.             switch (wParam) {
  1172.                 case VK_END:
  1173.                     if (!fShift)
  1174.                         ClearSelVLB (hWnd);
  1175.                     FillLB (GetParent (hWnd), sCount - sListSize);
  1176.                     sCaretIndex = sListSize - 1;
  1177.                     sScrollPos = sCount - sListSize;
  1178.                     break;
  1179.                     
  1180.                 case VK_HOME:
  1181.                     if (!fShift)
  1182.                         ClearSelVLB (hWnd);
  1183.                     FillLB (GetParent (hWnd), 0);
  1184.                     sCaretIndex = 0;            
  1185.                     sScrollPos = 0;
  1186.                     break;
  1187.                     
  1188.                 case VK_DOWN:
  1189.                     if (!fShift)
  1190.                         ClearSelVLB (hWnd);
  1191.                     if (sCaretIndex == sListSize - 1)
  1192.                         ScrollVLBDown (hWnd, 1, TRUE);
  1193.                     else
  1194.                         sCaretIndex++;
  1195.                     sScrollPos++;
  1196.                     break;
  1197.                     
  1198.                 case VK_UP:
  1199.                     if (!fShift)
  1200.                         ClearSelVLB (hWnd);
  1201.                     if (sCaretIndex == 0)
  1202.                         ScrollVLBUp (hWnd, 1, TRUE);
  1203.                     else                
  1204.                         sCaretIndex--;
  1205.                     sScrollPos--;
  1206.                     break;
  1207.  
  1208.                 case VK_NEXT:
  1209.                     if (!fShift)
  1210.                         ClearSelVLB (hWnd);
  1211.                     if (sCaretIndex > 0)
  1212.                         i = ScrollVLBDown (hWnd, sCaretIndex, fShift);
  1213.                     else
  1214.                         i = sListSize - 1;
  1215.                     sCaretIndex = sListSize - 1;
  1216.                     sScrollPos += i;
  1217.                     break;
  1218.  
  1219.                 case VK_PRIOR:
  1220.                     if (!fShift)
  1221.                         ClearSelVLB (hWnd);
  1222.                     if (sCaretIndex < sListSize - 1)
  1223.                         i = ScrollVLBUp (hWnd, sListSize - sCaretIndex - 1, fShift);
  1224.                     else
  1225.                         i = sListSize - 1;
  1226.                     sCaretIndex = 0;            
  1227.                     sScrollPos -= i;
  1228.                     break;
  1229.                     
  1230.                 default:
  1231.                     return CallWindowProc (lpfnOldLBoxWndProc, hWnd, wMsg,
  1232.                                            wParam, lParam);
  1233.             }
  1234.             SendMessage (hWnd, LB_SETSEL, TRUE, sCaretIndex);
  1235.             SendMessage (hWnd, LB_SETCARETINDEX, sCaretIndex, FALSE);
  1236.             SetScrollPos (hWnd, SB_VERT, sScrollPos, TRUE);
  1237.             return 0;
  1238.     }
  1239.     return CallWindowProc (lpfnOldLBoxWndProc, hWnd, wMsg,
  1240.                            wParam, lParam);
  1241. }
  1242. //============================================================
  1243. // RefreshDlgProc - Refresh dialog box dialog procedure
  1244. //============================================================
  1245. BOOL CALLBACK RefreshDlgProc (HWND hWnd, UINT wMsg, UINT wParam, 
  1246.                               LONG lParam) {
  1247.  
  1248.     INT sCnt, rc = 0, sDrives[26];
  1249.  
  1250.     switch (wMsg) {
  1251.         case WM_INITDIALOG:
  1252.             SetStatusBarText (hMain, "Refresh file list", 0);
  1253.             SendDlgItemMessage (hWnd, IDD_DRVLIST, LB_RESETCONTENT, 0, 0);
  1254.             SendDlgItemMessage (hWnd, IDD_DRVLIST, LB_DIR, 
  1255.                                 DDL_DRIVES | DDL_EXCLUSIVE, (LONG)(LPSTR)"*.*");
  1256.             return TRUE;
  1257.             
  1258.         case WM_COMMAND:
  1259.             switch (wParam) {
  1260.                 case IDD_REFRESH:
  1261.                     if (HIWORD(lParam) != BN_CLICKED)
  1262.                         return FALSE;
  1263.                 
  1264.                     if (fSearching) {
  1265.                         fSearching = FALSE;
  1266.                         SetDlgItemText (hWnd, IDD_REFRESH, "Refresh");
  1267.                     } else {
  1268.                         sCnt = (INT) SendDlgItemMessage (hWnd, IDD_DRVLIST, LB_GETSELCOUNT, 0, 0);
  1269.                         if (sCnt == 0) {
  1270.                             MessageBox (hWnd, "No drives selected.", "ThinDisk", 
  1271.                                         MB_OK | MB_ICONASTERISK);
  1272.                             return 0;
  1273.                         }
  1274.                         SetDlgItemText (hWnd, IDD_REFRESH, "Stop");
  1275.                         SendDlgItemMessage (hWnd, IDD_DRVLIST, LB_GETSELITEMS, 26, 
  1276.                                             (LONG)(LPINT)sDrives);
  1277.                     
  1278.                         SetStatusBarText (hMain, "Scanning drive(s)...", 0);
  1279.                         rc = ScanMachine (hWnd, sCnt, sDrives);
  1280.                         if (rc)
  1281.                             PrintError (hWnd, rc);
  1282.                         else
  1283.                             EndDialog(hWnd, 0);
  1284.                     }
  1285.                     fSearching = FALSE;
  1286.                     return TRUE;
  1287.                 
  1288.                 case IDOK:
  1289.                 case IDCANCEL:
  1290.                     fSearching = FALSE;
  1291.                     EndDialog(hWnd, 0);
  1292.                     return TRUE;
  1293.             }        
  1294.     } 
  1295.     return FALSE;
  1296. }
  1297. //============================================================
  1298. // MoveCopyDelDlgProc - Dialog procedure for Copy Move and Del
  1299. // dialog boxes.
  1300. //============================================================
  1301. BOOL CALLBACK MoveCopyDelDlgProc (HWND hWnd, UINT wMsg, UINT wParam, 
  1302.                                   LONG lParam) {
  1303.     static INT sNum;
  1304.     static HGLOBAL hBuff;
  1305.     static INT sFuncType;
  1306.     HGLOBAL hSet;
  1307.     INT i, sIndex, sCnt, sTemp, rc;
  1308.     LPLPMYDIRENTRY lpIndexPtr;
  1309.     LPLPMYDIRENTRY lpSetPtr;
  1310.     LPWORD lpArray;
  1311.     char *pszDir;
  1312.     char szFile[128];
  1313.     char szDest[128];
  1314.  
  1315.     switch (wMsg) {
  1316.         case WM_INITDIALOG:
  1317.             //Do Function specifc stuff
  1318.             sFuncType = (INT) lParam;
  1319.             if (sFuncType == 1) {
  1320.                 SetDlgItemText (hWnd, IDOK, "Move");
  1321.                 SetWindowText (hWnd, "Move Files");
  1322.                 SetWindowText (GetDlgItem (hWnd, IDD_COPYTEXT), 
  1323.                                "The following files/directories are to be moved:");
  1324.             }    
  1325.             //Init dlg controls
  1326.             SendDlgItemMessage (hWnd, IDD_FILELIST, LB_RESETCONTENT, 0, 0);
  1327.             SendDlgItemMessage (hWnd, IDD_FILELIST, LB_SETHORIZONTALEXTENT, 1000, 0);
  1328.             //Get a list of all selected files and place in listbox
  1329.             hBuff = GlobalAlloc (GHND, (LONG)sCount * sizeof (INT));
  1330.             if (hBuff == 0)
  1331.                 return TRUE;
  1332.             lpArray = (LPWORD) GlobalLock (hBuff);
  1333.             sNum = (INT)SendMessage (GetDlgItem (hMain, IDD_FLIST), 
  1334.                                      LB_GETSELCOUNT, 0, 0);
  1335.             SendMessage (GetDlgItem (hMain, IDD_FLIST), LB_GETSELITEMS, sNum, 
  1336.                                      (LONG)(LPWORD)lpArray);
  1337.             for (i = 0; i < sNum; i++) {
  1338.                 *(lpArray + i) = (INT)SendMessage (
  1339.                                             GetDlgItem (hMain, IDD_FLIST), 
  1340.                                             LB_GETITEMDATA, *(lpArray+i), 0L);
  1341.             }
  1342.             lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hSortSeg[sSortIndex]);
  1343.             for (i = 0; i < sCount; i++) {
  1344.                 if (((*(lpIndexPtr + i))->ucAttrib & ATTR_SELECTED) &&
  1345.                     !((*(lpIndexPtr + i))->ucAttrib & ATTR_DELETED)) {
  1346.                     *(lpArray + sNum) = i;
  1347.                     sNum++;
  1348.                 }    
  1349.             }                    
  1350.             for (i = 0; i < sNum; i++) {
  1351.                 sIndex = *(lpArray + i);
  1352.                 if (!((*(lpIndexPtr + sIndex))->ucAttrib & ATTR_DELETED)) { 
  1353.                     if ((*(lpIndexPtr + sIndex))->ucAttrib & _A_SUBDIR) 
  1354.                         strcpy (szFile, "Dir  ");
  1355.                     else    
  1356.                         strcpy (szFile, "File ");
  1357.                     sTemp = sizeof (szFile) - 5;                                                        
  1358.                     CreatePath (*(lpIndexPtr + sIndex), szFile+5, &sTemp);
  1359.                     SendDlgItemMessage (hWnd, IDD_FILELIST, LB_ADDSTRING, 0, 
  1360.                                         (LONG) (LPSTR) szFile);
  1361.                 }
  1362.             }
  1363.             GlobalUnlock (hBuff);
  1364.             GlobalUnlock (hSortSeg[sSortIndex]);
  1365.             return TRUE;
  1366.             
  1367.         case WM_COMMAND:
  1368.             switch (wParam) {
  1369.                 case IDOK:
  1370.                     //If move or copy, check out dest dir.
  1371.                     if (sFuncType < 2) {
  1372.                         OFSTRUCT of;
  1373.                         GetDlgItemText (hWnd, IDD_DESTPATH, szFile, sizeof (szFile));
  1374.                         _fullpath (szDest, szFile, sizeof (szDest));
  1375.                         OpenFile (szDest, &of, OF_EXIST);                 
  1376.                         if (of.nErrCode != 0) {
  1377.                             strcat (szDest, "\\COM");
  1378.                             OpenFile (szDest, &of, OF_EXIST);
  1379.                             szDest[strlen (szDest)-4] = '\0';
  1380.                             rc = 0;
  1381.                             if (of.nErrCode == 3)
  1382.                                 rc = mkdir (szDest);
  1383.                             if (rc) {
  1384.                                 MessageBox (hWnd,"Destination directory can\'t be created",
  1385.                                            szTitleText, MB_OK | MB_ICONHAND);
  1386.                                 return TRUE;
  1387.                             }                                        
  1388.                         } else
  1389.                             if (sNum > 1) {
  1390.                                 MessageBox (hWnd, 
  1391.                            "Destination can\'t be a file when multiple files selected",
  1392.                                            szTitleText, MB_OK | MB_ICONHAND);
  1393.                                 return TRUE;
  1394.                             }                                        
  1395.                     }    
  1396.                     lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hSortSeg[sSortIndex]);
  1397.                     lpArray = (LPWORD) GlobalLock (hBuff);
  1398.                     //Get each selected item in list box
  1399.                     rc = 0;
  1400.                     for (i = 0; (i < sNum) && (rc == 0); i++) {
  1401.                         sIndex = *(lpArray + i);
  1402.                         if (!((*(lpIndexPtr + sIndex))->ucAttrib & ATTR_DELETED)) { 
  1403.                             szFile[0] = '\0';
  1404.                             sTemp = sizeof (szFile);
  1405.                              CreatePath (*(lpIndexPtr + sIndex), szFile, &sTemp);
  1406.                             pszDir = szFile + strlen (szFile);
  1407.                             //If subdir, make call to get all files under the dir
  1408.                             if ((*(lpIndexPtr + sIndex))->ucAttrib & _A_SUBDIR) {
  1409.                                 sCnt = 0;
  1410.                                 hSet = GetIncludedSet (*(lpIndexPtr + sIndex), &sCnt);
  1411.                                 if (hSet) {
  1412.                                     lpSetPtr = (LPLPMYDIRENTRY) GlobalLock (hSet);
  1413.                                     for (i = 0; (i < sCnt) && (rc == 0); i++) {
  1414.                                         if (((*(lpSetPtr + i))->ucAttrib & _A_SUBDIR) == 0) {
  1415.                                             sTemp = sizeof (szFile);
  1416.                                             CreatePath (*(lpSetPtr + i), szFile, &sTemp);
  1417.                                             rc = (pFileFunc[sFuncType])(*(lpSetPtr + i), 
  1418.                                                                         pszDir, szFile, szDest);
  1419.                                         }    
  1420.                                     }
  1421.                                     GlobalUnlock (hSet);
  1422.                                 }
  1423.                                 GlobalFree (hSet);
  1424.                             } else {
  1425.                                 rc = (pFileFunc[sFuncType])(*(lpIndexPtr + sIndex), 
  1426.                                                             pszDir, szFile, szDest);
  1427.                             }
  1428.                         }
  1429.                     }
  1430.                     if (rc) 
  1431.                         PrintError (hWnd, rc);
  1432.                     GlobalUnlock (hSortSeg[sSortIndex]);
  1433.                     GlobalUnlock (hBuff);
  1434.                     GlobalFree (hBuff);
  1435.                     EndDialog(hWnd, rc);
  1436.                     return TRUE;
  1437.  
  1438.                 case IDCANCEL:
  1439.                     GlobalUnlock (hBuff);
  1440.                     GlobalFree (hBuff);
  1441.                     EndDialog(hWnd, ERR_CANCELED);
  1442.                     return TRUE;
  1443.             }        
  1444.     } 
  1445.     return FALSE;
  1446. }
  1447. //============================================================
  1448. // IncFilesDlgProc - Include files dialog box dialog procedure
  1449. // This procedure is also used by the Find Dialog
  1450. //============================================================
  1451. BOOL CALLBACK IncFilesDlgProc (HWND hWnd, UINT wMsg, UINT wParam, 
  1452.                                LONG lParam) {
  1453.     static LPINCSPEC lpSpec;
  1454.     char szTemp[40];
  1455.     char *pszTemp;
  1456.     INT i;
  1457.     BOOL fFail;
  1458.     UINT usDate;
  1459.                                             
  1460.     switch (wMsg) {
  1461.         case WM_INITDIALOG:
  1462.             if (lParam == 0) 
  1463.                 return FALSE;
  1464.             
  1465.             lpSpec = (LPINCSPEC) lParam;
  1466.             if ((lpSpec->fScrnFlags & DLG_INCLUDE) ||
  1467.                 (lpSpec->fScrnFlags & DLG_INCLUDEEDIT)) {
  1468.                 SendDlgItemMessage (hWnd, IDD_SPECNAME, EM_LIMITTEXT, 
  1469.                                    sizeof (lpSpec->szSpecName)-1, 0L);
  1470.                 SetDlgItemText (hWnd, IDD_SPECNAME, lpSpec->szSpecName);
  1471.             }
  1472.             SendDlgItemMessage (hWnd, IDD_FSPEC, EM_LIMITTEXT, 
  1473.                                sizeof (lpSpec->szFileSpec)-1, 0L);    
  1474.                 
  1475.             CheckDlgButton (hWnd, IDD_CHKFSPEC, lpSpec->fScrnFlags & SCRN_NAME);
  1476.             SetDlgItemText (hWnd, IDD_FSPEC, lpSpec->szFileSpec);
  1477.  
  1478.             CheckDlgButton (hWnd, IDD_CHKFSIZE, lpSpec->fScrnFlags & SCRN_SIZE);
  1479.             ltoa (lpSpec->lIncSize, szTemp, 10);
  1480.             SetDlgItemText (hWnd, IDD_FSIZE, szTemp);
  1481.             if (lpSpec->fScrnFlags & SCRN_SIZEB)
  1482.                 CheckDlgButton (hWnd, IDD_FSIZEDN, TRUE);
  1483.             else    
  1484.                 CheckDlgButton (hWnd, IDD_FSIZEUP, TRUE);
  1485.  
  1486.             CheckDlgButton (hWnd, IDD_CHKFDATE, lpSpec->fScrnFlags & SCRN_DATE);
  1487.             Date2asc (lpSpec->usIncDate, 0, szTemp);
  1488.             *strchr (szTemp, ' ') = '\0';  //Truncate time part of string
  1489.             SetDlgItemText (hWnd, IDD_FDATE, szTemp);
  1490.             CheckRadioButton (hWnd, IDD_FDATEB, IDD_FDATEO, 
  1491.                               IDD_FDATEB + (lpSpec->fScrnFlags & SCRN_BAE));
  1492.  
  1493.             CheckDlgButton (hWnd, IDD_CHKFATTRS, lpSpec->fScrnFlags & SCRN_ATTRS);
  1494.             CheckDlgButton (hWnd, IDD_CHKFARDONLY, lpSpec->usIncFlags & _A_RDONLY);
  1495.             CheckDlgButton (hWnd, IDD_CHKFAARCH, lpSpec->usIncFlags & _A_ARCH);
  1496.             CheckDlgButton (hWnd, IDD_CHKFAHIDDEN, lpSpec->usIncFlags & _A_HIDDEN);
  1497.             CheckDlgButton (hWnd, IDD_CHKFASYSTEM, lpSpec->usIncFlags & _A_SYSTEM);
  1498.             //Since this procedure is used for different dialog templates, 
  1499.             //use flags in ScrnFlags to config template specific stuff.
  1500.             if (lpSpec->fScrnFlags & DLG_INCLUDE) {
  1501.                 if (lpSpec->fScrnFlags & SCRN_INCDIRS) {
  1502.                     CheckDlgButton (hWnd, IDD_INCDIRS, TRUE);
  1503.                     EnableWindow (GetDlgItem (hWnd, IDD_INCEMPTYDIRS), TRUE);
  1504.                     if (!(lpSpec->fScrnFlags & SCRN_INCEMPTYDIRS))
  1505.                         CheckDlgButton (hWnd, IDD_INCEMPTYDIRS, TRUE);
  1506.                 } else
  1507.                     EnableWindow (GetDlgItem (hWnd, IDD_INCEMPTYDIRS), FALSE);
  1508.                 //Hide Save As button
  1509.                 ShowWindow (GetDlgItem (hWnd, IDD_SAVEAS), SW_HIDE);
  1510.             }            
  1511.             return TRUE;
  1512.             
  1513.         case WM_COMMAND:
  1514.             switch (wParam) {
  1515.                 
  1516.                 case IDD_INCDIRS:
  1517.                     if (IsDlgButtonChecked (hWnd, IDD_INCDIRS))
  1518.                         EnableWindow (GetDlgItem (hWnd, IDD_INCEMPTYDIRS), TRUE);
  1519.                     else {
  1520.                         CheckDlgButton (hWnd, IDD_INCEMPTYDIRS, FALSE);
  1521.                         EnableWindow (GetDlgItem (hWnd, IDD_INCEMPTYDIRS), FALSE);
  1522.                     }    
  1523.                     break;
  1524.                     
  1525.                 case IDD_SAVEAS:
  1526.                 case IDOK:
  1527.                         if ((lpSpec->fScrnFlags & DLG_INCLUDE) ||
  1528.                             (lpSpec->fScrnFlags & DLG_INCLUDEEDIT))  
  1529.                             GetDlgItemText (hWnd, IDD_SPECNAME, lpSpec->szSpecName, 
  1530.                                             sizeof (lpSpec->szSpecName));
  1531.                         lpSpec->fScrnFlags = 0;
  1532.                     // Get and verify filename spec
  1533.                     if (IsDlgButtonChecked (hWnd, IDD_CHKFSPEC)) {
  1534.                         lpSpec->fScrnFlags |= SCRN_NAME;
  1535.                         GetDlgItemText (hWnd, IDD_FSPEC, szTemp, sizeof (szTemp));
  1536.                         strupr (szTemp);
  1537.                         if (strpbrk (szTemp, ":\\")) {
  1538.                             PrintError (hWnd, ERR_BADNAME);
  1539.                             return TRUE;
  1540.                         }
  1541.                         lstrcpy (lpSpec->szFileSpec, szTemp);
  1542.                     }    
  1543.                     // Get and verify size spec
  1544.                     if (IsDlgButtonChecked (hWnd, IDD_CHKFSIZE)) {
  1545.                         GetDlgItemText (hWnd, IDD_FSIZE, szTemp, sizeof (szTemp));
  1546.                         for (i = 0; i < (INT) strlen (szTemp); i++)
  1547.                             if (!isdigit (szTemp[i]))    {
  1548.                                 PrintError (hWnd, ERR_BADSIZE);
  1549.                                 return TRUE;
  1550.                             }
  1551.                         lpSpec->lIncSize = atol (szTemp);
  1552.                         lpSpec->fScrnFlags |= SCRN_SIZE;
  1553.                         if (IsDlgButtonChecked (hWnd, IDD_FSIZEDN))
  1554.                             lpSpec->fScrnFlags |= SCRN_SIZEB;
  1555.                         else    
  1556.                             lpSpec->fScrnFlags &= ~SCRN_SIZEB;
  1557.                     }    
  1558.                     // Get and verify date spec
  1559.                     if (IsDlgButtonChecked (hWnd, IDD_CHKFDATE)) {
  1560.                         GetDlgItemText (hWnd, IDD_FDATE, szTemp, sizeof (szTemp));
  1561.                         fFail = FALSE;
  1562.                         usDate = 0;
  1563.                         i = atoi (szTemp);
  1564.                         if ((i < 1) || (i > 12))
  1565.                             fFail = TRUE;
  1566.                         else
  1567.                             usDate |= i << 5;
  1568.                         i = 0;
  1569.                         pszTemp = strchr (szTemp, '-');
  1570.                         if (pszTemp)
  1571.                             i = atoi (pszTemp+1);
  1572.                         if ((i < 1) || (i > 31))     //No, I didn't bother to check
  1573.                             fFail = TRUE;             //specific month lengths.
  1574.                         else
  1575.                             usDate |= i;
  1576.                         i = -1;
  1577.                         pszTemp = strchr (pszTemp+1, '-');
  1578.                         if (pszTemp)
  1579.                             i = atoi (pszTemp+1) - 1980;
  1580.                         if (i < 0)
  1581.                             fFail = TRUE;
  1582.                         else
  1583.                             usDate |= i << 9;
  1584.  
  1585.                         if (fFail) {
  1586.                                 PrintError (hWnd, ERR_BADDATE);
  1587.                                 return TRUE;
  1588.                             }
  1589.                         lpSpec->usIncDate = usDate;
  1590.                         lpSpec->fScrnFlags |= SCRN_DATE;
  1591.                         lpSpec->fScrnFlags &= ~SCRN_BAE;
  1592.                         if (IsDlgButtonChecked (hWnd, IDD_FDATEA))
  1593.                             lpSpec->fScrnFlags |= 1;
  1594.                         else if (IsDlgButtonChecked (hWnd, IDD_FDATEO))
  1595.                             lpSpec->fScrnFlags |= 2;
  1596.                     }    
  1597.                     // Get and verify attribute spec
  1598.                     if (IsDlgButtonChecked (hWnd, IDD_CHKFATTRS)) {
  1599.                         lpSpec->usIncFlags = 0;
  1600.                         if (IsDlgButtonChecked (hWnd, IDD_CHKFARDONLY))
  1601.                             lpSpec->usIncFlags |= _A_RDONLY;
  1602.                         if (IsDlgButtonChecked (hWnd, IDD_CHKFAARCH))
  1603.                             lpSpec->usIncFlags |= _A_ARCH;
  1604.                         if (IsDlgButtonChecked (hWnd, IDD_CHKFAHIDDEN))
  1605.                             lpSpec->usIncFlags |= _A_HIDDEN;
  1606.                         if (IsDlgButtonChecked (hWnd, IDD_CHKFASYSTEM))
  1607.                             lpSpec->usIncFlags |= _A_SYSTEM;
  1608.                         lpSpec->fScrnFlags |= SCRN_ATTRS;
  1609.                     }    
  1610.                     //Check directory flags
  1611.                     if (IsDlgButtonChecked (hWnd, IDD_INCDIRS)) {
  1612.                         lpSpec->fScrnFlags |= SCRN_INCDIRS;
  1613.                         if (IsDlgButtonChecked (hWnd, IDD_INCEMPTYDIRS))
  1614.                             lpSpec->fScrnFlags |= SCRN_INCEMPTYDIRS;
  1615.                     }
  1616.                     if (wParam == IDD_SAVEAS)
  1617.                         EndDialog(hWnd, 2);
  1618.                     else    
  1619.                         EndDialog(hWnd, 1);
  1620.                     return TRUE;
  1621.  
  1622.                 case IDCANCEL:
  1623.                     EndDialog(hWnd, 0);
  1624.                     return TRUE;
  1625.             }
  1626.             break;
  1627.     } 
  1628.     return FALSE;
  1629. }
  1630. //============================================================
  1631. // IncludeDelDlgProc - Delete Set dialog box dialog procedure
  1632. //============================================================
  1633. BOOL CALLBACK IncludeDelDlgProc (HWND hWnd, UINT wMsg, UINT wParam, 
  1634.                                  LONG lParam) {
  1635.     INT i;
  1636.  
  1637.     switch (wMsg) {
  1638.         case WM_INITDIALOG:
  1639.             SendDlgItemMessage (hWnd, IDD_INCLIST, LB_RESETCONTENT, 0, 0);
  1640.             for (i = 1; i < sIncCount; i++)
  1641.                 SendDlgItemMessage (hWnd, IDD_INCLIST, LB_ADDSTRING, 0,
  1642.                                     (LONG)(LPSTR)incArray[i].szSpecName);
  1643.             if (lParam) {
  1644.                 SetDlgItemText (hWnd, IDOK, "Edit");
  1645.                 SetWindowText (hWnd, "Edit Include Set");
  1646.             }    
  1647.             return TRUE;
  1648.             
  1649.         case WM_COMMAND:
  1650.             switch (wParam) {
  1651.                 case IDOK:
  1652.                      i = (INT) SendDlgItemMessage (hWnd, IDD_INCLIST, 
  1653.                                                   LB_GETCURSEL, 0, 0);
  1654.                     if (i == LB_ERR) {
  1655.                         EndDialog(hWnd, 0);
  1656.                     } else    
  1657.                         EndDialog(hWnd, i+1);
  1658.                     return TRUE;
  1659.                     
  1660.                 case IDCANCEL:
  1661.                     EndDialog(hWnd, 0);
  1662.                     return TRUE;
  1663.             }        
  1664.     } 
  1665.     return FALSE;
  1666. }
  1667. //============================================================
  1668. // AboutDlgProc - About dialog box dialog procedure
  1669. //============================================================
  1670. BOOL CALLBACK AboutDlgProc (HWND hWnd, UINT wMsg, UINT wParam, 
  1671.                             LONG lParam) {
  1672.     char    szAboutStr[128];
  1673.                               
  1674.     if (wMsg == WM_INITDIALOG) {
  1675.         GetDlgItemText (hWnd, IDD_PROGSTR, szAboutStr, sizeof (szAboutStr));
  1676.         itoa ((INT)lParam/10, &szAboutStr[strlen (szAboutStr)], 10);
  1677.         strcat (szAboutStr, ".");
  1678.         itoa ((INT)lParam%10, &szAboutStr[strlen (szAboutStr)], 10);
  1679.         SetDlgItemText (hWnd, IDD_PROGSTR, szAboutStr);
  1680.         return TRUE;
  1681.     }   
  1682.     if (wMsg == WM_COMMAND) 
  1683.        if ((wParam == IDOK) || (wParam == IDCANCEL)) {
  1684.             EndDialog(hWnd, 0);
  1685.             return TRUE;
  1686.         } 
  1687.     return FALSE;
  1688. }
  1689. //------------------------------------------------------------
  1690. // GetFListPos - Compute the size and position of the files
  1691. // listbox.
  1692. //------------------------------------------------------------ 
  1693. void GetFListPos (HWND hWnd, RECT *rectOut) {
  1694.     RECT rect;
  1695.     
  1696.     GetClientRect (hWnd, &rect);
  1697.     ModifyClientRect (hWnd, &rect);
  1698.     *rectOut = rect;
  1699.     return;
  1700. }    
  1701. //------------------------------------------------------------
  1702. // CopyFile - Copies a file
  1703. //------------------------------------------------------------ 
  1704. INT CopyFile (LPMYDIRENTRY lpEntry, char *pszName, char *pszSrc, char *pszDest) {
  1705.     char szTemp[128];
  1706.     char szTemp1[128];
  1707.     char *pszTemp;
  1708.     char *pszEnd;
  1709.     OFSTRUCT ofFile;
  1710.  
  1711.     if (strlen (pszSrc) + strlen (pszDest) > sizeof (szTemp))
  1712.         return ERR_NAMETOOLONG;
  1713.     //Create destination file name
  1714.     strcpy (szTemp, pszDest);
  1715.     strcat (szTemp, pszName);
  1716.     pszEnd = strrchr (szTemp, '\\');
  1717.     //See if dest path exists. 
  1718.     OpenFile (szTemp, &ofFile, OF_EXIST);
  1719.     if (ofFile.nErrCode == 3) { 
  1720.         *pszEnd = '\0';
  1721.         //Back up path until a dir is found.  rc 3 is path not found.
  1722.         while (ofFile.nErrCode == 3) {
  1723.             pszTemp = strrchr (szTemp, '\\');
  1724.             if (pszTemp == 0)    return 3;
  1725.             if (*(pszTemp-1) == ':')
  1726.                 pszTemp++;
  1727.             *pszTemp = '\0';
  1728.             strcpy (szTemp1, szTemp);
  1729.             strcat (szTemp1, "\\COM");
  1730.             OpenFile (szTemp1, &ofFile, OF_EXIST);
  1731.         }
  1732.         // Make directories until dest dir created
  1733.         while (szTemp + strlen (szTemp) < pszEnd) {
  1734.             szTemp[strlen (szTemp)] = '\\';
  1735.             mkdir (szTemp);
  1736.         }
  1737.         *pszEnd = '\\';
  1738.     }    
  1739.     return MyCopyFile (pszSrc, szTemp);            
  1740. }    
  1741. //------------------------------------------------------------
  1742. // DeleteFile - Deletes a file
  1743. //------------------------------------------------------------ 
  1744. INT DeleteFile (LPMYDIRENTRY lpEntry, char *pszName, char *pszSrc,
  1745.                 char *pszDest) {
  1746.     INT rc;
  1747.     
  1748.     rc = remove (pszSrc);
  1749.     if (rc == 0)
  1750.         lpEntry->ucAttrib |= ATTR_DELETED;
  1751.     return rc;
  1752. }    
  1753. //------------------------------------------------------------
  1754. // MoveFile - Moves a file
  1755. //------------------------------------------------------------ 
  1756. INT MoveFile (LPMYDIRENTRY lpEntry, char *pszName, char *pszSrc,
  1757.               char *pszDest) {
  1758.     INT rc;
  1759.                           
  1760.     rc = CopyFile (lpEntry, pszSrc, pszName, pszDest);
  1761.     if (rc == 0)
  1762.         rc = DeleteFile (lpEntry, pszSrc, pszName, pszDest);
  1763.     return rc;
  1764. }    
  1765. //------------------------------------------------------------
  1766. // PrintError - Displays a message box with an error code
  1767. //------------------------------------------------------------ 
  1768. void    PrintError (HWND hWnd, INT rc) {
  1769.     char szErrStr[80];
  1770.     char szTemp[12];
  1771.     
  1772.     if (rc > 0)
  1773.        rc += DOSERROFFSET;
  1774.     else 
  1775.        rc = abs (rc);
  1776.     if (LoadString (hInst, rc, szErrStr, sizeof (szErrStr)) == 0) {
  1777.         itoa (rc, szTemp, 10);
  1778.         strcpy (szErrStr, "Error number: ");
  1779.         strcat (szErrStr, szTemp);
  1780.     }
  1781.     MessageBox (hMain, szErrStr, szTitleText, MB_OK | MB_ICONHAND);
  1782.     return;
  1783. }
  1784. //------------------------------------------------------------
  1785. // AddIncSet - Adds an include set to the include list
  1786. //------------------------------------------------------------
  1787. INT AddIncSet (HWND hWnd, PINCSPEC pincData) {
  1788.     INT i, rc;
  1789.     
  1790.     //If too many specs, overwrite the oldest one
  1791.     if (sIncCount >= MAXINCSPECS) {
  1792.         for (i = 1; i < MAXINCSPECS - 1; i++)
  1793.             incArray[i] = incArray[i+1];
  1794.     } else
  1795.         sIncCount++;
  1796.     if (strlen (pincData->szSpecName) == 0) {
  1797.         strcpy (pincData->szSpecName, "Set ");
  1798.         itoa (sIncCount, &pincData->szSpecName[strlen (pincData->szSpecName)], 10);
  1799.     }
  1800.     memcpy (&incArray[sIncCount-1], pincData, sizeof (INCSPEC));
  1801.     lpCurrInc = &incArray[sIncCount-1];
  1802.     sOldIncCnt = 0;    //Force menu regen on next menu init.
  1803.  
  1804.     //Get include set
  1805.     rc = GetIncludedFiles (hWnd);
  1806.     if (rc) {
  1807.         PrintError (hWnd, rc);
  1808.         return 0;
  1809.     }        
  1810.     FillLB (hWnd, 0);
  1811.     DisplayCurrStatus (hWnd);
  1812.     return 0;
  1813. }
  1814. //------------------------------------------------------------
  1815. // FillLB - Clears, then refills the hot key listbox
  1816. //------------------------------------------------------------ 
  1817. void FillLB (HWND hWnd, INT sStart) {
  1818.     INT i;
  1819.  
  1820.     SendDlgItemMessage (hWnd, IDD_FLIST, LB_RESETCONTENT, 0, 0);
  1821.     if (sStart > sCount - 1) 
  1822.         return;
  1823.     
  1824.     for (i = sStart; (i < sStart + sListSize) && (i < sCount); i++)  
  1825.         SendDlgItemMessage (hWnd, IDD_FLIST, LB_ADDSTRING, 0, 
  1826.                             (LPARAM) (LONG) i);
  1827.     SetScrollRange (GetDlgItem (hWnd, IDD_FLIST), SB_VERT, 0, 
  1828.                     sCount - sListSize, FALSE);
  1829.     SetScrollPos (GetDlgItem (hWnd, IDD_FLIST), SB_VERT, sStart, TRUE);
  1830.     return;
  1831. }    
  1832. //------------------------------------------------------------
  1833. // DisplayCurrStatus - Creates a text string describing the 
  1834. // current status, then displays it in the status bar.
  1835. //------------------------------------------------------------ 
  1836. void DisplayCurrStatus (HWND hWnd) {
  1837.     char szTemp[80];
  1838.     
  1839.     if (sMasterCount == 0)
  1840.         SetStatusBarText (hWnd, "Select Refresh under the Files menu to list files", 0);
  1841.     else {
  1842.         if (sCount <= 1) 
  1843.             SetStatusBarText (hWnd, "No files found", 0);
  1844.         else {        
  1845.             lstrcpy (szTemp, lpCurrInc->szSpecName);
  1846.             strcat (szTemp, " sorted by ");
  1847.             strcat (szTemp, szSortLabel [sSortIndex]);
  1848.             SetStatusBarText (hWnd, szTemp, 0);
  1849.         }
  1850.         ltoa ((LONG) max (sCount-sDirCnt, 0), szTemp, 10);
  1851.         if (lpCurrInc->fScrnFlags & SCRN_INCDIRS) {
  1852.             itoa (sCount, szTemp, 10);
  1853.             strcat (szTemp, " Directories and files");
  1854.         } else {
  1855.             itoa (max (sCount-sDirCnt, 0), szTemp, 10);
  1856.             strcat (szTemp, " Files");
  1857.         }    
  1858.         SetStatusBarText (hWnd, szTemp, 1);
  1859.     }    
  1860.     return;
  1861. }
  1862. //------------------------------------------------------------
  1863. // The following routines are used to convert find data to
  1864. // ASCII text strings
  1865. //------------------------------------------------------------
  1866. //------------------------------------------------------------
  1867. // CreatePath - Builds a path string
  1868. //------------------------------------------------------------ 
  1869. void CreatePath (LPMYDIRENTRY lpEntry, char *pszOut, int *psSize) {
  1870.     INT i;
  1871.     
  1872.     if (lpEntry->lpParent) {
  1873.         CreatePath (lpEntry->lpParent, pszOut, psSize);
  1874.     } else {
  1875.         lstrcat (pszOut, lpEntry->szName+1);
  1876.         pszOut[2] = 0;
  1877.         return;
  1878.     }    
  1879.     i = lstrlen (lpEntry->szName);        
  1880.     if (*psSize    < i) {
  1881.         *psSize = 0;
  1882.         return;
  1883.     }    
  1884.     strcat (pszOut, "\\");
  1885.     lstrcat (pszOut, lpEntry->szName);
  1886.     *psSize -= (i+1);
  1887.     return;
  1888. }        
  1889. //------------------------------------------------------------
  1890. // Date2asc - Convert DOS date to ASCII string
  1891. // Date              Time 
  1892. //    15-9 Year        15-11 Hours
  1893. //     8-5 Month       10-5  Minutes
  1894. //     4-0 Day          4-0  Seconds * 2
  1895. //------------------------------------------------------------ 
  1896. void Date2asc (UINT usDate, UINT usTime, char *pszOut) {
  1897.     UINT usTemp;
  1898.     if (usDate == 0xffff) {
  1899.         *pszOut = '\0';
  1900.         return;
  1901.     }
  1902.     *pszOut++ = (char)((((usDate >> 5) & 0x0f) / 10) + 0x30);
  1903.     *pszOut++ = (char)((((usDate >> 5) & 0x0f) % 10) + 0x30);
  1904.     *pszOut++ = '-';    
  1905.  
  1906.     *pszOut++ = (char)(((usDate & 0x1f) / 10) + 0x30);
  1907.     *pszOut++ = (char)(((usDate & 0x1f) % 10) + 0x30);
  1908.     *pszOut++ = '-';    
  1909.     
  1910.     usTemp = ((usDate >> 9) & 0x7f) + 1980;
  1911.     itoa ((INT) usTemp, pszOut, 10);
  1912.     pszOut += 4;
  1913.     *pszOut++ = ' ';    
  1914.     *pszOut++ = ' ';    
  1915.     *pszOut++ = ' ';    
  1916.     *pszOut++ = ' ';    
  1917.     
  1918.     usTemp = ((usTime >> 11) & 0x1f);
  1919.     if (usTemp > 11)
  1920.         *(pszOut+5) = 'p';
  1921.     else    
  1922.         *(pszOut+5) = 'a';
  1923.     if (usTemp > 12)
  1924.         usTemp -= 12;
  1925.         
  1926.     *pszOut++ = (char)((usTemp / 10) + 0x30);
  1927.     *pszOut++ = (char)((usTemp % 10) + 0x30);
  1928.     *pszOut++ = ':';    
  1929.     usTemp = ((usTime >> 5) & 0x3f);
  1930.     *pszOut++ = (char)((usTemp / 10) + 0x30);
  1931.     *pszOut++ = (char)((usTemp % 10) + 0x30);
  1932.     //Seconds are not displayed
  1933.     *(pszOut+1) = '\0';    
  1934.         
  1935.     return;
  1936. }    
  1937. //------------------------------------------------------------
  1938. // Attr2asc - Convert DOS attribute flags to ASCII string
  1939. //------------------------------------------------------------ 
  1940. void Attr2asc (BYTE ucAttrib, char *pszOut) {
  1941.  
  1942.     strcpy (pszOut, "----");
  1943.     if (ucAttrib & _A_RDONLY)
  1944.         *pszOut = 'r';
  1945.     pszOut++;
  1946.     if (ucAttrib & _A_ARCH)
  1947.         *pszOut = 'a';
  1948.     pszOut++;
  1949.     if (ucAttrib & _A_SYSTEM)
  1950.         *pszOut = 's';
  1951.     pszOut++;
  1952.     if (ucAttrib & _A_HIDDEN)
  1953.         *pszOut = 'h';
  1954.     return;
  1955. }    
  1956. //------------------------------------------------------------
  1957. // The following routines are used by the Find and include
  1958. // set functions.
  1959. //------------------------------------------------------------
  1960. //------------------------------------------------------------
  1961. // ScreenFile - Determines if a file entry matches a set of
  1962. // characteristics.
  1963. //------------------------------------------------------------ 
  1964. BOOL ScreenFile (LPMYDIRENTRY lpEntry, LPINCSPEC lpSpec) {
  1965.  
  1966.     BOOL fInclude = TRUE;
  1967.     char far *lpTemplate;
  1968.     char far *lpName;
  1969.  
  1970.     //See if file already deleted.            
  1971.     if (lpEntry->ucAttrib & ATTR_DELETED)
  1972.         return FALSE;
  1973.     //Check file name
  1974.     if (lpSpec->fScrnFlags & SCRN_NAME) {
  1975.         lpName = lpEntry->szName;
  1976.         lpTemplate = lpSpec->szFileSpec;
  1977.         while (fInclude && (*lpTemplate != '\0')) {
  1978.             if (*lpTemplate == '?') {
  1979.                 ;
  1980.             } else if (*lpTemplate == '*') {
  1981.                 while ((*lpName != '\0') &&
  1982.                        (*lpName != *(lpTemplate+1)))
  1983.                     lpName++;
  1984.                 lpTemplate++;
  1985.             } else
  1986.                 if (*lpName != *lpTemplate)
  1987.                     fInclude = FALSE;
  1988.             lpTemplate++;
  1989.             if (*lpName != '\0')
  1990.                 lpName++;
  1991.         }        
  1992.     }    
  1993.     //Check file date
  1994.     if (fInclude && (lpSpec->fScrnFlags & SCRN_DATE)) {
  1995.         switch (lpSpec->fScrnFlags & SCRN_BAE) {
  1996.             case 0:
  1997.                 if (lpEntry->usDate > lpSpec->usIncDate)
  1998.                     fInclude = FALSE;
  1999.                 break;    
  2000.             case 1:
  2001.                 if (lpEntry->usDate < lpSpec->usIncDate)
  2002.                     fInclude = FALSE;
  2003.                 break;    
  2004.             case 2:
  2005.                 if (lpEntry->usDate != lpSpec->usIncDate)
  2006.                     fInclude = FALSE;
  2007.                 break;    
  2008.         }        
  2009.     }
  2010.     //Check file size
  2011.     if (fInclude && (lpSpec->fScrnFlags & SCRN_SIZE)) {
  2012.         if (lpSpec->fScrnFlags & SCRN_SIZEB) {
  2013.             if (lpEntry->lSize >= lpSpec->lIncSize)
  2014.                 fInclude = FALSE;
  2015.         } else {
  2016.             if (lpEntry->lSize < lpSpec->lIncSize)
  2017.                 fInclude = FALSE;
  2018.         }        
  2019.     }    
  2020.     //Check file attributes
  2021.     if (fInclude && (lpSpec->fScrnFlags & SCRN_ATTRS)) {
  2022.         if (!(lpEntry->ucAttrib & (BYTE) lpSpec->usIncFlags))
  2023.             fInclude = FALSE;
  2024.     }    
  2025.     return fInclude;
  2026. }    
  2027. //------------------------------------------------------------
  2028. // GetIncludedDir - Scans a directory for files matching the
  2029. // requested criteria.
  2030. //------------------------------------------------------------ 
  2031. INT GetIncludedDir (LPMYDIRENTRY lpParent, LPLPMYDIRENTRY lpEndPtr, 
  2032.                     INT *psNum) {
  2033.     INT sSubNum;
  2034.     LPMYDIRENTRY lpEntryPtr;
  2035.  
  2036.     lpEntryPtr = *lpIndexPtr;
  2037.     while ((lpEndPtr > lpIndexPtr) &&
  2038.            (lpEntryPtr->lpParent == lpParent)) {
  2039.     
  2040.         lpIndexPtr++;
  2041.         if (lpEntryPtr->ucAttrib & _A_SUBDIR) {
  2042.             lpEntryPtr->lSize = 0;
  2043.             lpEntryPtr->usDate = 0;
  2044.             lpEntryPtr->usTime = 0;
  2045.             sSubNum = 0;
  2046.             GetIncludedDir (lpEntryPtr, lpEndPtr, &sSubNum);
  2047.             if ((lpCurrInc->fScrnFlags & SCRN_INCDIRS) &&
  2048.                 (sSubNum || (lpCurrInc->fScrnFlags & SCRN_INCEMPTYDIRS))) {
  2049.                 *lpDestPtr++ = lpEntryPtr;
  2050.                 sSubNum++;
  2051.                 sDirCnt++;
  2052.             } 
  2053.             lpParent->lSize += lpEntryPtr->lSize;
  2054.             if (sSubNum) {
  2055.                 if ((lpParent->usDate < lpEntryPtr->usDate) ||
  2056.                     ((lpParent->usDate == lpEntryPtr->usDate) && 
  2057.                      (lpParent->usTime < lpEntryPtr->usTime))) {
  2058.                     lpParent->usDate = lpEntryPtr->usDate;
  2059.                     lpParent->usTime = lpEntryPtr->usTime;
  2060.                 }
  2061.             }
  2062.             *psNum += sSubNum;
  2063.         } else {
  2064.             if (ScreenFile (lpEntryPtr, lpCurrInc)) {
  2065.                 *lpDestPtr++ = lpEntryPtr;
  2066.                 //Add file size to that of parent.  Update date as well.
  2067.                 lpParent->lSize += lpEntryPtr->lSize;
  2068.                 if ((lpParent->usDate < lpEntryPtr->usDate) ||
  2069.                     ((lpParent->usDate == lpEntryPtr->usDate) && 
  2070.                      (lpParent->usTime < lpEntryPtr->usTime))) {
  2071.                     lpParent->usDate = lpEntryPtr->usDate;
  2072.                     lpParent->usTime = lpEntryPtr->usTime;
  2073.                 }
  2074.                 (*psNum)++;
  2075.             }    
  2076.         }        
  2077.         lpEntryPtr = *lpIndexPtr;
  2078.     }
  2079.     return 0;
  2080. }
  2081. //------------------------------------------------------------
  2082. // GetIncludedSet - Creates a subset index array that matches the
  2083. // current include spec characteristics.
  2084. //------------------------------------------------------------ 
  2085. HGLOBAL GetIncludedSet (LPMYDIRENTRY lpStartDir, INT *psCnt) {
  2086.     HGLOBAL hGlobal;
  2087.     INT i;
  2088.     LPLPMYDIRENTRY lpEndPtr;
  2089.  
  2090.     if (sMasterCount == 0)
  2091.         return 0;
  2092.         
  2093.     lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hMasterSeg);
  2094.     lpEndPtr = lpIndexPtr + sMasterCount - 1;
  2095.     for (i = 0;i < sMasterCount; i++)
  2096.         if (*lpIndexPtr++ == lpStartDir)
  2097.             break;
  2098.  
  2099.     hGlobal = GlobalAlloc (GHND, (LONG)(sMasterCount - i) *
  2100.                                        sizeof (LPMYDIRENTRY));
  2101.     if (hGlobal == 0)
  2102.         return 0;
  2103.  
  2104.     lpDestPtr = (LPLPMYDIRENTRY) GlobalLock (hGlobal);
  2105.     *psCnt = 0;
  2106.     GetIncludedDir (lpStartDir, lpEndPtr, psCnt);
  2107.     GlobalUnlock (hGlobal);
  2108.     GlobalUnlock (hMasterSeg);
  2109.     return hGlobal;
  2110. }    
  2111. //------------------------------------------------------------
  2112. // GetIncludedFiles - Creates an index array that matches the
  2113. // current include spec characteristics.
  2114. //------------------------------------------------------------ 
  2115. INT GetIncludedFiles (HWND hWnd) {
  2116.     INT i, rc = 0, sSubNum;
  2117.     LPLPMYDIRENTRY lpEndPtr;
  2118.     LPMYDIRENTRY lpHeaderPtr;
  2119.     LPMYDIRENTRY lpEntryPtr;
  2120.  
  2121.     //Free all sorted arrays    
  2122.     for (i = 0; i < SORTTYPES; i++)
  2123.         if (hSortSeg[i]) {
  2124.             GlobalFree (hSortSeg[i]);
  2125.             hSortSeg[i] = 0;
  2126.         }    
  2127.     if (sMasterCount == 0)
  2128.         return 0;            
  2129.     hSortSeg[sSortIndex] = GlobalAlloc (GHND, (LONG)sMasterCount *
  2130.                                               sizeof (LPMYDIRENTRY));
  2131.     if (hSortSeg[sSortIndex] == 0)
  2132.         return ERR_OUTOFMEM;
  2133.  
  2134.     lpDestPtr = (LPLPMYDIRENTRY) GlobalLock (hSortSeg[sSortIndex]);
  2135.     lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hMasterSeg);
  2136.  
  2137.     SetStatusBarText (hWnd, "Screening files...", 0);
  2138.  
  2139.     lpEndPtr = lpIndexPtr + sMasterCount - 1;
  2140.     lpHeaderPtr = *lpIndexPtr;
  2141.     
  2142.     *lpDestPtr++ = *lpIndexPtr++;          //Copy Search header entry
  2143.     lpHeaderPtr->lSize = 0;
  2144.     lpHeaderPtr->usDate = 0;
  2145.     lpHeaderPtr->usTime = 0;
  2146.     sCount = 1;
  2147.     sDirCnt = 1;
  2148.     
  2149.     lpEntryPtr = *lpIndexPtr++;
  2150.     while (lpEndPtr > lpIndexPtr)  {
  2151.         lpEntryPtr->lSize = 0;
  2152.         lpEntryPtr->usDate = 0;
  2153.         lpEntryPtr->usTime = 0;
  2154.         sSubNum = 0;
  2155.         GetIncludedDir (lpEntryPtr, lpEndPtr, &sSubNum);
  2156.         if (sSubNum) {
  2157.             *lpDestPtr++ = lpEntryPtr;
  2158.             sSubNum++;
  2159.         }    
  2160.         lpHeaderPtr->lSize += lpEntryPtr->lSize;
  2161.         if ((lpHeaderPtr->usDate < lpEntryPtr->usDate) ||
  2162.             ((lpHeaderPtr->usDate == lpEntryPtr->usDate) && 
  2163.              (lpHeaderPtr->usTime < lpEntryPtr->usTime))) {
  2164.              lpHeaderPtr->usDate = lpEntryPtr->usDate;
  2165.              lpHeaderPtr->usTime = lpEntryPtr->usTime;
  2166.         }
  2167.         sCount += sSubNum;
  2168.         sDirCnt++;
  2169.         lpEntryPtr = *lpIndexPtr++;
  2170.     }
  2171.     GlobalUnlock (hMasterSeg);
  2172.     GlobalUnlock (hSortSeg[sSortIndex]);
  2173.  
  2174.     if (sCount) {
  2175.         lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hSortSeg[sSortIndex]);
  2176.         rc = MyQSort (lpIndexPtr, sCount, (PSORTFUNC) pSortFunc[sSortIndex]);
  2177.         GlobalUnlock (hSortSeg[sSortIndex]);
  2178.     }        
  2179.     return rc;
  2180. }    
  2181. //============================================================  
  2182. // Scan and sort routines
  2183. //============================================================  
  2184. //------------------------------------------------------------
  2185. // FreeBuffer - Frees all buffers
  2186. //------------------------------------------------------------ 
  2187. INT FreeBuffer (UINT selBuffIn) {
  2188.     LPBUFFHDR lpBuffPtr;
  2189.     UINT selNext;
  2190.  
  2191.     while (selBuffIn) {
  2192.         lpBuffPtr = MAKELP (selBuffIn, 0);
  2193.         selNext = lpBuffPtr->selNext;
  2194.         GlobalUnlock (selBuffIn);
  2195.         GlobalFree (selBuffIn);
  2196.         selBuffIn = selNext;
  2197.     }        
  2198.     return 0;
  2199. }
  2200. //------------------------------------------------------------
  2201. // GetBuffBlock - Allocates and inits a buffer.
  2202. //------------------------------------------------------------ 
  2203. INT GetBuffBlock (LPBUFFHDR lpBuff, UINT usOldSize) {
  2204.     HGLOBAL hMem;
  2205.     UINT usSize;
  2206.     LPBUFFHDR lpNewBuff;
  2207.     
  2208.     usSize = ((0x10000 - sizeof (BUFFHDR)) / sizeof (MYDIRENTRY)) * 
  2209.              sizeof (MYDIRENTRY);
  2210.     hMem = GlobalAlloc (GHND, usSize);
  2211.  
  2212.     if (hMem == 0)
  2213.         return ERR_OUTOFMEM;
  2214.     lpNewBuff = (LPBUFFHDR) GlobalLock (hMem);
  2215.     
  2216.     lpBuff->selNext = SELECTOROF (lpNewBuff);
  2217.     lpBuff->usEnd = usOldSize;
  2218.     lpNewBuff->usSize = usSize;
  2219.     
  2220.     lpCurrBuff = MAKELP (SELECTOROF (lpNewBuff), 0);
  2221.     lpDirEntry = (LPMYDIRENTRY) (lpCurrBuff + 1);
  2222.     return 0;
  2223. }
  2224. //------------------------------------------------------------
  2225. // ScanDir - Copies the contents of a directory into the
  2226. // file name buffer.
  2227. //------------------------------------------------------------ 
  2228. INT ScanDir (HWND hWnd, LPMYDIRENTRY lpParent) {
  2229.     FIND_T fs;
  2230.     char *pszSrchDirEnd;
  2231.     int i, rc;
  2232.     UINT far *lpwDest;
  2233.     UINT *pwSrc;
  2234.  
  2235.     pszSrchDirEnd = szSearchDir + strlen (szSearchDir);
  2236.     strcpy (pszSrchDirEnd, "\\*.*");
  2237.  
  2238.     rc = _dos_findfirst (szSearchDir, _A_RDONLY | _A_ARCH | 
  2239.                         _A_HIDDEN | _A_SYSTEM | _A_SUBDIR, &fs);
  2240.  
  2241.     while ((rc == 0) && (fSearching)) {
  2242.         //
  2243.         //Display directory count as a progress report
  2244.         //
  2245.         if ((sDirCnt % 20) == 0) {
  2246.             ltoa (sDirCnt, pszStatEnd, 10);
  2247.             SetDlgItemText (hWnd, IDD_REFRESHTEXT, szStatText);
  2248.         }    
  2249.        MyYield ();                                        //Yield to other apps
  2250.         if (!fSearching)
  2251.             return ERR_CANCELED;
  2252.         //
  2253.         // See if current buffer filled
  2254.         //
  2255.         lpDirEntry++;
  2256.         if (OFFSETOF (lpDirEntry) >= lpCurrBuff->usSize) {
  2257.             rc = GetBuffBlock (lpCurrBuff, OFFSETOF (lpDirEntry));
  2258.             if (rc)
  2259.                 return rc;        
  2260.         }
  2261.         //
  2262.         // Copy directory entry
  2263.         //
  2264.         pwSrc = (UINT *) &fs.attrib;
  2265.         lpwDest = (UINT far *)lpDirEntry;
  2266.         //Save parent pointer
  2267.         *((LPLONG)lpwDest)++ = (LONG)lpParent;
  2268.         //Copy Dir entry
  2269.         for (i = 2; i < sizeof (MYDIRENTRY)/2; i++)
  2270.             *lpwDest++ = *pwSrc++;
  2271.         //Clear flags I hide in attribute byte
  2272.         lpDirEntry->ucAttrib &= ~(ATTR_DELETED | ATTR_SELECTED);
  2273.         //
  2274.         //If subdir, recurse
  2275.         //
  2276.         if (fs.attrib & _A_SUBDIR) {
  2277.             sDirCnt++;
  2278.             if ((strcmp (fs.name, ".") != 0) &&
  2279.                (strcmp (fs.name, "..") != 0)) {
  2280.  
  2281.                 *lpIndexPtr++ = lpDirEntry;
  2282.                 sMasterCount++;
  2283.                 *pszSrchDirEnd = '\\';
  2284.                 strcpy (pszSrchDirEnd+1, fs.name);
  2285.                 rc = ScanDir (hWnd, lpDirEntry);
  2286.                 if (rc == 0x12)
  2287.                     rc = 0;
  2288.             }            
  2289.         } else {
  2290.             *lpIndexPtr++ = lpDirEntry;
  2291.             sMasterCount++;
  2292.         }    
  2293.         //
  2294.         // Add entry to index
  2295.         //
  2296.         if (sMasterCount > MAXCOUNT)
  2297.             rc = ERR_TOOMANYFILES;
  2298.         if (rc == 0)    
  2299.             rc = _dos_findnext (&fs);
  2300.     }
  2301.     return rc;
  2302. }    
  2303. //------------------------------------------------------------
  2304. // ScanDisk - Search a specific drive
  2305. //------------------------------------------------------------ 
  2306. INT ScanDisk (HWND hWnd, LPMYDIRENTRY lpParent, INT sDiskNum) {
  2307.     INT rc;
  2308.     LPMYDIRENTRY lpDrvEntry;
  2309.  
  2310.     lpDirEntry++;
  2311.     if (OFFSETOF (lpDirEntry) >= lpCurrBuff->usSize) {
  2312.         rc = GetBuffBlock (lpCurrBuff, OFFSETOF (lpDirEntry));
  2313.         if (rc)
  2314.             return rc;        
  2315.     }
  2316.     sMasterCount++;
  2317.     if (sMasterCount > MAXCOUNT)
  2318.         rc = ERR_TOOMANYFILES;
  2319.     *lpIndexPtr++ = lpDirEntry;
  2320.     lpDrvEntry = lpDirEntry;
  2321.         
  2322.     lpDrvEntry->lpParent = 0;
  2323.     lpDrvEntry->ucAttrib = ATTR_DELETED;
  2324.     lpDrvEntry->usTime = 0;
  2325.     lpDrvEntry->usDate = 0;
  2326.     lpDrvEntry->lSize = 0;            
  2327.     lstrcpy (lpDrvEntry->szName, " C:\\");
  2328.     lpDrvEntry->szName[1] = (char) (sDiskNum + 0x40);
  2329.  
  2330.     _chdrive (sDiskNum);
  2331.     chdir ("\\");
  2332.     szSearchDir[0] = '\0';
  2333.     rc = ScanDir (hWnd, lpDirEntry);
  2334.     lpParent->lSize += lpDrvEntry->lSize;
  2335.     return rc;
  2336. }
  2337. //------------------------------------------------------------
  2338. // ScanMachine - Performs the entire search
  2339. //------------------------------------------------------------ 
  2340. INT ScanMachine (HWND hWnd, INT sCnt, INT *sDrives) {
  2341.     INT i, rc;
  2342.     char szDrv[10];
  2343.     LPMYDIRENTRY lpSrchEntry;
  2344.     
  2345.     //Free old buffers    
  2346.     FreeBuffer (Buff.selNext);
  2347.     if (hMasterSeg) 
  2348.         GlobalFree (hMasterSeg);
  2349.     for (i = 0; i < SORTTYPES; i++)
  2350.         if (hSortSeg[i]) {
  2351.             GlobalFree (hSortSeg[i]);
  2352.             hSortSeg[i] = 0;
  2353.         }
  2354.         
  2355.     //Alloc buffs for dir entries and index    
  2356.     rc = GetBuffBlock (&Buff, 0);
  2357.     if (rc) 
  2358.         return rc;
  2359.     hMasterSeg = GlobalAlloc (GHND, (LONG)MAXCOUNT * sizeof (LPLPMYDIRENTRY));
  2360.     if (hMasterSeg == 0)
  2361.         rc = ERR_OUTOFMEM;
  2362.  
  2363.     sMasterCount = 1;
  2364.     fSearching = TRUE;    
  2365.     lpIndexPtr = (LPLPMYDIRENTRY) GlobalLock (hMasterSeg);
  2366.     *lpIndexPtr++ = lpDirEntry;
  2367.     lpSrchEntry = lpDirEntry;
  2368.     
  2369.     lpSrchEntry->lpParent = 0;
  2370.     lpSrchEntry->ucAttrib = ATTR_DELETED;  
  2371.     lpSrchEntry->usTime = 0;
  2372.     lpSrchEntry->usDate = 0;
  2373.     lpSrchEntry->lSize = 0;
  2374.     lstrcpy (lpSrchEntry->szName, "  Search");
  2375.  
  2376.     for (i = 0; (i < sCnt) && (rc == 0); i++) {
  2377.         SendDlgItemMessage (hWnd, IDD_DRVLIST, LB_GETTEXT, sDrives[i],
  2378.                             (LONG)(LPSTR)szDrv);
  2379.         strcpy (szStatText, "Scanning Disk ");
  2380.         strcat (szStatText, szDrv);
  2381.         SetDlgItemText (hWnd, IDD_REFRESHTEXT, szStatText);
  2382.         strcat (szStatText, "\nDirs: ");
  2383.         pszStatEnd = szStatText + strlen (szStatText);    
  2384.         strupr (szDrv);
  2385.         rc = ScanDisk (hWnd, lpSrchEntry, szDrv[2]-(BYTE)0x40);
  2386.         if (rc == 0x12)
  2387.             rc = 0;
  2388.     }
  2389.     GlobalUnlock (hMasterSeg);
  2390.     fSearching = FALSE;    
  2391.     //Shrink the index block down to size necessary.
  2392.     hMasterSeg = GlobalReAlloc (hMasterSeg, (LONG)sMasterCount * 
  2393.                                 sizeof (LPLPMYDIRENTRY), GMEM_ZEROINIT);
  2394.     if (hMasterSeg == 0)
  2395.         rc = ERR_OUTOFMEM;
  2396.     return rc;
  2397. }
  2398. //------------------------------------------------------------
  2399. // InvertIndex - Invert an index
  2400. //------------------------------------------------------------ 
  2401. void InvertIndex (HPDWORD lpSrc, UINT usCnt) {
  2402.     DWORD dwTemp;
  2403.     HPDWORD lpDest;
  2404.  
  2405.     lpDest = lpSrc + usCnt - 1;
  2406.     while (lpDest >= lpSrc) {
  2407.         dwTemp = *lpDest;
  2408.         *lpDest = *lpSrc;
  2409.         *lpSrc = dwTemp;
  2410.         lpSrc++;
  2411.         lpDest--;
  2412.     }            
  2413.     return;
  2414. }                                
  2415. //------------------------------------------------------------
  2416. // SortDate - Sorts entries by file date
  2417. //------------------------------------------------------------
  2418. INT SortDate (LPVOID lpSrc, LPVOID lpDest) {
  2419.     UINT usTemp;
  2420.  
  2421.     usTemp = ((LPMYDIRENTRY)*(LPDWORD)lpDest)->usDate -
  2422.             ((LPMYDIRENTRY)*(LPDWORD)lpSrc)->usDate;
  2423.     if (usTemp)
  2424.         return (INT) usTemp;
  2425.     usTemp = ((LPMYDIRENTRY)*(LPDWORD)lpDest)->usTime -
  2426.             ((LPMYDIRENTRY)*(LPDWORD)lpSrc)->usTime;
  2427.     if (usTemp)
  2428.         return (INT) usTemp;
  2429.     return SortName (lpSrc, lpDest);
  2430. }    
  2431. //------------------------------------------------------------
  2432. // SortSize - Sorts entries by file size
  2433. //------------------------------------------------------------
  2434. INT SortSize (LPVOID lpSrc, LPVOID lpDest) {
  2435.     LONG lTemp;
  2436.  
  2437.     lTemp = ((LPMYDIRENTRY)*(LPDWORD)lpDest)->lSize -
  2438.            ((LPMYDIRENTRY)*(LPDWORD)lpSrc)->lSize;
  2439.     if (lTemp < 0)
  2440.         return -1;
  2441.     if (lTemp > 0)
  2442.         return 1;
  2443.     return SortName (lpSrc, lpDest);
  2444. }    
  2445. //------------------------------------------------------------
  2446. // SortExt - Sorts entries by file ext
  2447. //------------------------------------------------------------
  2448. INT SortExt (LPVOID lpSrc, LPVOID lpDest) {
  2449.     char far *pszSrc, far *pszDest;
  2450.     INT rc;
  2451.  
  2452.     pszSrc = ((LPMYDIRENTRY)*(LPDWORD)lpSrc)->szName;
  2453.     pszDest = ((LPMYDIRENTRY)*(LPDWORD)lpDest)->szName;
  2454.     while ((*pszSrc != '\0') && (*pszSrc != '.'))
  2455.         pszSrc++;
  2456.     while ((*pszDest != '\0') && (*pszDest != '.'))
  2457.         pszDest++;
  2458.  
  2459.     rc = lstrcmp (pszSrc,pszDest);
  2460.     if (rc)
  2461.         return rc;        
  2462.     return SortName (lpSrc, lpDest);
  2463. }    
  2464. //------------------------------------------------------------
  2465. // SortName - Sorts entries by filename
  2466. //------------------------------------------------------------
  2467. INT SortName (LPVOID lpSrc, LPVOID lpDest) {
  2468.     return lstrcmp (((LPMYDIRENTRY)*(LPDWORD)lpSrc)->szName,
  2469.                     ((LPMYDIRENTRY)*(LPDWORD)lpDest)->szName);
  2470. }    
  2471. //------------------------------------------------------------
  2472. // MyQSort1 - A quick sort routine 
  2473. //------------------------------------------------------------
  2474. INT MyQSort1 (HPDWORD lpBase, UINT usNum, PSORTFUNC pFunc) {
  2475.     INT rc;
  2476.     UINT usHigh, usEven, usLow;
  2477.     HPDWORD lpHigh, lpLow;
  2478.     DWORD dwPiv, dwVal;
  2479.  
  2480.     usLevel++;
  2481.     if (usLevel > 500)
  2482.         return ERR_TOODEEP;
  2483.     //Compute and display status        
  2484.     usItteration++;        
  2485.     usHigh = (UINT) ((LONG) usItteration/(LONG)usGoal);
  2486.     if (((usHigh % 5) == 0) && (usLastStat != usHigh)) {
  2487.         usLastStat = usHigh;
  2488.         ltoa (usHigh, pszStatEnd, 10);
  2489.         strcat (pszStatEnd, "%");
  2490.         SetStatusBarText (hMain, szStatText, 0);
  2491.     }    
  2492.     //Yield to other apps
  2493.    MyYield ();
  2494.     if (!fSearching)
  2495.         return ERR_CANCELED;
  2496.  
  2497.     lpLow = lpBase;
  2498.     lpHigh = lpBase + (usNum - 1);
  2499.      
  2500. //Pick random Pivot.  Choose 1st element for simplicity
  2501.     dwPiv = *lpLow;
  2502.     dwVal = *lpHigh;
  2503.     usLow = usEven = 0;
  2504. //Move smaller elements above pivot
  2505.     while (lpLow < lpHigh) {
  2506.         rc = ((SORTFUNC)pFunc)(&dwPiv, &dwVal);
  2507.         if (rc >= 0) {
  2508.             *lpLow++ = dwVal;
  2509.             dwVal = *lpLow;
  2510.             usLow++;
  2511.             if (rc == 0)
  2512.                 usEven++;
  2513.         } else {
  2514.             *lpHigh-- = dwVal;
  2515.             dwVal = *lpHigh;
  2516.         }
  2517.     }
  2518.     *lpLow++ = dwPiv;
  2519.     usHigh = usNum - usLow;
  2520.     rc = 0;
  2521. //if more that two below, sort elements below pivot
  2522.     if (usLow > 1)
  2523.         rc = MyQSort1 (lpBase, usLow, pFunc);
  2524.  
  2525. //if more that two above, sort elements above pivot
  2526.     if ((usHigh > 2) && (rc == 0))
  2527.         rc = MyQSort1 (lpLow, usHigh-1, pFunc);
  2528.  
  2529.     usLevel--;
  2530.     return rc;
  2531. }
  2532. //------------------------------------------------------------
  2533. // MyQSort - QuickSort setup routine
  2534. //------------------------------------------------------------
  2535. INT MyQSort (HPDWORD lpBase, UINT usNum, PSORTFUNC pFunc) {
  2536.     INT rc;
  2537.     
  2538.     if (usNum < 2)
  2539.         return 0;
  2540.  
  2541.     fSearching = TRUE;
  2542.     usItteration = 0;
  2543.     usLevel = 0;
  2544.     usLastStat = -1;
  2545.     usGoal = (sCount / 138) + 1;
  2546.     strcpy (szStatText, "Sorting ");
  2547.     pszStatEnd = szStatText + strlen (szStatText);    
  2548.     rc = MyQSort1 (lpBase, usNum,  pFunc);
  2549.     if (fSortUp)
  2550.         InvertIndex (lpBase, usNum);
  2551.     fSearching = FALSE;
  2552.     return rc;
  2553. }    
  2554. //============================================================  
  2555. // General Helper Routines 
  2556. //============================================================  
  2557. //------------------------------------------------------------
  2558. // MyDisplayDialog - Display a dialog box
  2559. //------------------------------------------------------------ 
  2560. INT MyDisplayDialog (HINSTANCE hInstance, LPCSTR szDlgName,
  2561.                      HWND hWnd, WNDPROC lpDialogProc, 
  2562.                      LPARAM lParam) {
  2563.     WNDPROC lpDlgProcInst;
  2564.     INT        rc;
  2565.  
  2566.     lpDlgProcInst = MakeProcInstance(lpDialogProc, hInst);
  2567.     rc = DialogBoxParam (hInstance, szDlgName, hWnd, 
  2568.                          lpDlgProcInst, lParam);
  2569.     FreeProcInstance(lpDlgProcInst);
  2570.     return rc;                              
  2571. }
  2572. //------------------------------------------------------------
  2573. // MyWritePrivateProfileInt - Writes an integer to the profile
  2574. //------------------------------------------------------------
  2575. BOOL MyWritePrivateProfileInt (char *szSec, char *szEntry, 
  2576.                                int Num, int Base, char *szProfile) {
  2577.     char    szStr[33];
  2578.                                
  2579.     itoa (Num, szStr, Base);
  2580.     return WritePrivateProfileString (szSec, szEntry, szStr, 
  2581.                                       szProfile);
  2582. }
  2583. //------------------------------------------------------------
  2584. // MySubClassWindow - Subclasses a window 
  2585. //------------------------------------------------------------
  2586. WNDPROC MySubClassWindow (HWND hWnd, WNDPROC lpfnNewProc) {
  2587.    WNDPROC lpfnOldProc;
  2588.  
  2589.     lpfnOldProc = (WNDPROC) GetWindowLong (hWnd, GWL_WNDPROC);
  2590.     SetWindowLong (hWnd, GWL_WNDPROC, (LONG) lpfnNewProc);
  2591.     return lpfnOldProc;                               
  2592. }                               
  2593. //------------------------------------------------------------
  2594. // MyYield - Yields control to other programs, but returns
  2595. // if Windows is idle.
  2596. //------------------------------------------------------------
  2597. BOOL MyYield (void) {
  2598.    MSG    msg;
  2599.    BOOL    bCont;
  2600.    
  2601.    bCont = TRUE;
  2602.     while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {
  2603.        if (msg.message == WM_QUIT)
  2604.           bCont = FALSE;
  2605.         TranslateMessage(&msg);
  2606.         DispatchMessage(&msg);
  2607.     }
  2608.     return bCont;
  2609. }
  2610. //------------------------------------------------------------
  2611. // MyCopyFile - Copy a file
  2612. //------------------------------------------------------------
  2613. #define COPYBUFFSIZE 0xf000    
  2614. INT MyCopyFile (char *szSrcFile, char *szDestFile) {
  2615.     
  2616.     int        rc, i;
  2617.     HFILE        hSrc, hDest;
  2618.     HGLOBAL    hMem;
  2619.     UINT        usByteCnt;
  2620.     OFSTRUCT    ofFile;
  2621.     LPSTR        lpBuffer;
  2622.     DOSERR    doserr;
  2623.     
  2624.     // Open Source file
  2625.     hSrc = OpenFile (szSrcFile, &ofFile, OF_READ);
  2626.     if (hSrc == -1) 
  2627.         return ofFile.nErrCode;
  2628.  
  2629.     // Open Destination file, first, append src filename.
  2630.     i = strlen (szDestFile);
  2631.     if (szDestFile[i-1] != '\\')
  2632.         strcat (szDestFile, strrchr (szSrcFile, '\\'));
  2633.     else
  2634.          strcat (szDestFile, strrchr (szSrcFile, '\\')+1);
  2635.  
  2636.     hDest = OpenFile (szDestFile, &ofFile, OF_CREATE);
  2637.     if (hDest == -1) {
  2638.         // If path not found error, delete src filename
  2639.         if (ofFile.nErrCode == 3) {
  2640.             szDestFile[i] ='\0';
  2641.             hDest = OpenFile (szDestFile, &ofFile, OF_CREATE);
  2642.         }
  2643.         if (hDest == -1) {
  2644.             _lclose (hSrc);
  2645.             return ofFile.nErrCode;
  2646.         } 
  2647.     }
  2648.     // Allocate memory for a copy buffer
  2649.     rc = 0;
  2650.     hMem = GlobalAlloc (GHND, (LONG) COPYBUFFSIZE);
  2651.     if (hMem != 0) {
  2652.         lpBuffer = GlobalLock (hMem);
  2653.         while (rc == 0) {
  2654.             usByteCnt = _lread (hSrc, lpBuffer, COPYBUFFSIZE);
  2655.             if (usByteCnt == 0xFFFF)
  2656.                 rc = dosexterr (&doserr);
  2657.             else {
  2658.                 usByteCnt = _lwrite (hDest, lpBuffer, usByteCnt);
  2659.                 if (usByteCnt == 0xFFFF)
  2660.                     rc = dosexterr (&doserr);
  2661.             }
  2662.             if (usByteCnt < COPYBUFFSIZE)
  2663.                 break;
  2664.         }
  2665.         // Clean up
  2666.         GlobalUnlock (hMem);
  2667.         GlobalFree (hMem);
  2668.     } else
  2669.         rc = ERR_OUTOFMEM;
  2670.     _lclose (hSrc);
  2671.     _lclose (hDest);
  2672.     return rc;
  2673. }
  2674.